如果想要知道怎么求凸包的直徑
先去學習一下怎么求解凸包
點這里去看凸包
好了
現在知道了凸包是什么
我們很顯然可以得出,品面內最遠的點對一定在凸包上面(為啥自己想呀)
而凸包的直徑也就是凸包上最遠點對的距離。
繼續,考慮如何求解最遠點對
暴力枚舉?
顯然不一定所有點都會在凸包上,顯然比O(n^2)的枚舉的效率會更加優秀(但是求解凸包還有一個O(nlogn))
那么,有沒有什么好方法能夠求解出最遠點對的距離呢?
先來看一個凸包
考慮如何求解距離某一個點最遠的點呢?
我們轉換一下思路,如果一個點到某一條邊的距離最遠,那么就可以推出他到這條邊的兩個端點中的一個一定是最遠的。(自己證明,可能我說錯了。。。。)
所以,我們依次枚舉凸包上的每一條邊
計算一下哪個點到他的距離最遠,然后計算一下距離
但是,如果就是這樣依次枚舉的話
時間復雜度依舊是O(n^2)
似乎並沒有什么優化
先給凸包標上點
假設我現在考慮的是AB邊和他距離最遠的點
很顯然,D點距離他最遠
換條邊,換成BC邊
這個時候變成了E點
再繼續?
看看CD邊
這個時候又變成了A點
好了!
我們現在來看看發生了什么
我們的邊依次是: AB->BC->CD
而點依次是:D->E->A
發生了一件很神奇的事情
我們的邊是逆時針的枚舉
而此時距離他們最遠的點也是逆時針的出現!!
好了
如果自己分析一下
我們就不難得出
隨着邊逆時針枚舉,
所對應的點也是逆時針出現的
那么,這個時候,利用這個性質,
我們只需要逆時針枚舉邊,然后從上次枚舉到的最遠點繼續逆時針向后枚舉就能求解。
這個時候,O(n^2)被優化到了O(n)
恩,這樣求解就會很快了
於是
來轉一張動圖大致的看一看是怎么弄的
還是細節上的小問題
怎么判斷當前的距離是否更大
最直接的方法,用點到直線的距離公式(自己百度)
另外,還有一種方法
我們來看看
對於任意一條邊而言
其他的點離他的距離,就是過這個點做平行線到當前的邊的距離
而邊的長度是固定的,
距離越遠,那么,邊和點連成的面積也就越大。
還記得上回講凸包的時候,
我寫道:叉積可以用來求面積
那么,這里直接用叉積計算面積即可判斷點是否更遠。
這就是為啥要單獨介紹一下叉積可以用來求解面積。
說到這里差不多了
還是代碼(核心)
long long GetMax()//求出直徑
{
rg long long re=0;
if(top==1)//僅有兩個點
return Dis(S[0],S[1]);
S[++top]=S[0];//把第一個點放到最后
int j=2;
for(int i=0;i<top;++i)//枚舉邊
{
while(Cross(S[i],S[i+1],S[j])<Cross(S[i],S[i+1],S[j+1]))
j=(j+1)%top;
re=max(re,max(Dis(S[i],S[j]),Dis(S[i+1],S[j])));
}
return re;
}
老樣子,給你一道模板題
戳我
旋轉卡殼的具體實現還是看一看題目吧~