蜂窝小区最短距离实现 (极坐标+等差数列,十行代码搞定)

题目描述:由正六边形组成的蜂窝小区中,每个正六边形的编号如图所示。求任意2点间的距离。(规定最大编号不超过100000)

 

真的是Python十行代码搞定,估计C++也是十几行的代码。分析题目,提炼数学模型,再写代码。


这个题可以不用各种复杂的算法,从数学角度解决。用数学思维简化逻辑模型,而不是用计算机逻辑代替数学思维……
四大常用坐标系:笛卡尔直角坐标,极坐标,柱坐标,球坐标。这道题应该采用极坐标!加上等差数列!就够了~

firstValue, secondValue为给的2点,Python代码如下:

 1     n_fir = int(math.ceil((1+math.sqrt(1 + 4*(firstValue-1)/3))/2))
 2     n_sec = int(math.ceil((1+math.sqrt(1 + 4*(secondValue-1)/3))/2))
 3     if firstValue == 1:
 4         shortestPathLength = n_sec-1
 5     elif secondValue == 1:
 6         shortestPathLength = n_fir-1
 7     else:
 8         angle_fir = (n_fir*(n_fir-1)*3+1-firstValue)*2*math.pi/(6*(n_fir-1))
 9         angle_sec = (n_sec*(n_sec-1)*3+1-secondValue)*2*math.pi/(6*(n_sec-1))
10         shortestPathLength = round(math.sqrt((n_fir-1)**2+(n_sec-1)**2-2*(n_fir-1)*(n_sec-1)*math.cos(angle_fir-angle_sec)))
11     return int(shortestPathLength)

 

 

详细解释如下:

极坐标确定一个点,两点之间的距离公式  

图中可以用归纳法总结出等差数列:

圈号(等于极坐标轴长r-1) 容量 最小编号 最大编号
1 1(用0代替) 1(用0代替) 1(用0代替)
2 6(6*1) 2 7
3 12(6*2) 8 19
4 18(6*3) 20 37
5 24(6*4) 38 61

 

 

 

 

 

 

 

把第一圈的容量假设为0,最小最大编号假设为0,就是等差数列。(说明我们可以对含有编号1的特殊处理,其他的编号可以一起处理)

数字1、2、3、...、N-1、N,的隐含条件是:1)数字是有秩序(index)的,2)数字的秩序数(index)恰好等于该秩序处数字的值。

等差数列通项公式、求和公式

这里初值 a1 = 0, 公差d = 6

那么,Sn = ((圈号*(圈号-1))/2)*d + 1;  (最后加1是因为我们把a1=0了,实际编号从1开始的,所以这里加上)

 

给定编号怎么算位于第几圈呢?

对求和公式整理得,n^2 -n -2*Sn/d = 0,把编号赋给Sn,解一元二次方程,因为△>0,所以有解:

 根据公式舍弃一个负根,剩下的一个正跟就是解n(一个小数),对n向上取整,就是该编号对应的圈号。

向上取整:把离散的圈号看成连续的,那么(2,3]区间是属于第3圈。

极坐标定位:(设圈号为n, 已知点p)

 = n-1

 = ((n*(n-1)/2)*d + 1 - p)*π*/(d*(n-1)); π = 3.14...(圆周率),意思就是(第n圈的最大编号-给定的编号)*(圆周率/该圈的容量)!

所以,给定两个点p1, p2,用求出距离,再四舍五入,就是任意2点间的距离!

四舍五入:连接任意两个蜂窝的中心,会发现连线是对称的。

最后,注意下,如果给定的2个点含有1,那么直接返回[另一个的圈号-1]

 

posted @ 2016-07-26 23:24  水墨禅心  阅读(2544)  评论(1编辑  收藏  举报