Square spiral

Square spiral

Nikola picks up a strange circuit board. All of its elements are connected in a spiral and it is possible to connect the neighboring elements vertically and horizontally.

The map of the circuit consists of a series of square cells. The first element in the center is marked as 1, and continuing in a clockwise spiral, each other elements is marked in ascending order. On the map, you can move (connect cells) vertically and horizontally. You can help Nikola find the manhattan distance between any two elements on the map. For example, the distance between cells 1 and 9 is two moves and the distance between 24 and 9 is one move.

Input: Two marks of cells as an integers.

Output: The manhattan distance between the two cells as an integer.

原题链接:http://www.checkio.org/mission/strange-curcuit/

题目大义:找出两点在图上的曼哈顿距离

思路:首先观察得到,图中的数字由边数为2,4,6,8...的子正方形组成,而每个子正方形的数字个数有通项公式,为8*n + 4,如[1, 2, 3, 4],[5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],然后每个子正方形的最大数字的值可以通过累加子正方形的数字个数得到,为[4, 16, 36, ...]。有了子正方形最大数字序列后,可判断给定的点在几号子正方形上,并以该最大值作为坐标圆点,向左为x轴正向,向上为y轴正向,求出该点在该子正方形上的坐标。分别得到两点在相应子正方形中的坐标后,内侧子坐标加上两个子正方形的序号差即可统一坐标系,最后距离为abs(x1 - x2) + abs(y1 - y2)

 1 def search_for_subsquare(number, sub_square_max_numbers):
 2     mlen = len(sub_square_max_numbers)
 3     for i in range(mlen):
 4         if number <= sub_square_max_numbers[i]:
 5             return i
 6 
 7 def cal_relative_position(sub_square_line_number, max_number_in_sub_square, number):
 8     pos = [0, 0]
 9 
10     itr_number = max_number_in_sub_square
11 
12     if itr_number == number:
13         return pos
14 
15     direction = [1, 0, 1, 0] #up left down right
16     move = [1, 1, -1, -1] #+ + - -
17 
18     for pos_mv, each_dir in enumerate(direction):
19         for i in range(sub_square_line_number - 1): #range(4) means range(0, 4)
20             itr_number -= 1
21             pos[each_dir] += move[pos_mv]
22             if itr_number == number:
23                 return pos
24 
25 
26 def find_distance(first, second):
27     sub_square_number_counts = [(8 * n + 4) for n in range(64)]
28 
29     sub_square_max_numbers = [4]
30 
31     len_count = len(sub_square_number_counts)
32 
33     for i in range(1, len_count):
34         sub_square_max_numbers.append(sub_square_max_numbers[i - 1] + sub_square_number_counts[i])
35 
36     #search first and second in which sub_square
37     first_square = search_for_subsquare(first, sub_square_max_numbers)
38     second_square = search_for_subsquare(second, sub_square_max_numbers)
39 
40     #cal relative position in its sub_square
41     pos_first = cal_relative_position((first_square + 1) * 2, sub_square_max_numbers[first_square], first)
42     pos_second = cal_relative_position((second_square + 1) * 2, sub_square_max_numbers[second_square], second)
43 
44     #unify relative postition and cal manhatan dist
45     if first_square > second_square:
46         scale = first_square - second_square
47         pos_second[0] += scale
48         pos_second[1] += scale
49     else:
50         scale = second_square - first_square
51         pos_first[0] += scale
52         pos_first[1] += scale
53 
54     return abs(pos_first[0] - pos_second[0]) + abs(pos_first[1] - pos_second[1])

review Sim0000's codes

 1 from math import sqrt
 2  
 3 # calculate the coordinate of n
 4 def coord(n):
 5     if n == 1: return (0, 0)
 6     r = int(sqrt(n - 1) - 1) // 2 + 1
 7     g, d = divmod(n - (2*r-1)**2 - 1, 2*r)
 8     return [(-r+d+1, r), (r, r-d-1), (r-d-1, -r), (-r, -r+d+1)][g]
 9  
10 def find_distance(first, second):
11     x1, y1 = coord(first)
12     x2, y2 = coord(second)
13     return abs(x2 - x1) + abs(y2 - y1)
14  
15     # At first, we determine ring which include n
16     #   ring 0 : 1
17     #   ring 1 : 2,3,...,9
18     #   ring 2 : 10,11,...,25
19     #   ring r : (2*r-1)**2+1,...,(2*r+1)**2
20     # Using following formula, we can calculate r from n.
21     #   r = int((sqrt(n - 1) - 1) / 2) + 1
22     # Ring r have 8*r elements and start position is (-r+1, r).
23     # And another interesting position is follows.
24     #   (-r,  r) : left upper corner,  n = (2*r-1)**2 + 8*r = (2*r+1)**2
25     #   ( r,  r) : right upper corner, n = (2*r-1)**2 + 2*r
26     #   ( r, -r) : right lower corner, n = (2*r-1)**2 + 4*r
27     #   (-r, -r) : left lower corner,  n = (2*r-1)**2 + 6*r
28     #
29     # Second, I divide ring into 4 groups corresponding to the direction.
30     # Each group size is 2*r. The group 0 is the first 2*r elements of the ring
31     # and its direction is right, and so on.
32     #   group 0 (dir = R) : n is from (2*r-1)**2    +1 to (2*r-1)**2+2*r
33     #   group 1 (dir = D) : n is from (2*r-1)**2+2*r+1 to (2*r-1)**2+4*r
34     #   group 2 (dir = L) : n is from (2*r-1)**2+4*r+1 to (2*r-1)**2+6*r
35     #   group 3 (dir = U) : n is from (2*r-1)**2+6*r+1 to (2*r-1)**2+8*r
36     # Using following formula, we can calculate group number g from n, r.
37     #   g = int((n - (2*r-1)**2 - 1) / (2*r)
38     #
39     # Finally, using above information, we will calulate the coordinate of n.
40     # When n belongs to group 0 of ring r, then the coordinate of n is
41     # (-r+1 + d, r), where d means n is the d-th elements of the group.
42     # As well, we can calculate for another groups.
43     #   group 0 : (-r+1+d, r)
44     #   group 1 : (r, r-1+d)
45     #   group 2 : (r-1-d, r)
46     #   group 3 : (-r, -r+d+1)

用的是数学方法,有时间再仔细看了

posted @ 2014-08-17 08:57  哲人善思  阅读(309)  评论(0编辑  收藏  举报