題目描述:由正六邊形組成的蜂窩小區中,每個正六邊形的編號如圖所示。求任意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]