演算法目的
演算法步驟:
①首先現將所有點隨機排列
②按順序把點乙個乙個的加入(一步一步的求前i個點的最小覆蓋圓),每加入乙個點就進入③
③如果發現當前i號點在當前的最小圓的外面,那麼說明點i一定在前i個點的最小覆蓋圓邊界上,我們轉到④來進一步確定這個圓,否則前i個點的最小覆蓋圓與前i-1個點的最小覆蓋圓是一樣的,則不需要更新,返回②
④此時已經確認點i一定在前i個點的最小覆蓋圓的邊界上了,那麼我們可以把當前圓的圓心設為第i個點,半徑為0,然後重新把前i-1個點加入這個圓中(類似上面的步驟,只不過這次我們提前確定了點i在圓上,目的是一步一步求出包含點i的前j個點的最小覆蓋圓),每加入乙個點就進入⑤
⑤如果發現當前j號點在當前的最小圓的外面,那麼說明點j也一定在前j個點(包括i)的最小覆蓋圓邊界上,我們轉到⑥來再進一步確定這個圓,否則前j個點(包括i)的最小覆蓋圓與前i-1個點(包括i)的最小覆蓋圓是一樣的,則不需要更新,返回④
⑥此時已經確認點i,j一定在前j個點(包括i)的最小覆蓋圓的邊界上了,那麼我們可以把當前圓的圓心設為第i個點與第j的點連線的中點,半徑為到這兩個點的距離(就是找乙個覆蓋這兩個點的最小圓),然後重新把前j-1個點加入這個圓中(還是類似上面的步驟,只不過這次我們提前確定了兩個點在圓上,目的是求出包含點i,j的前k個點的最小覆蓋圓),每加入乙個點就進入⑦
⑦如果發現當前k號點在當前的最小圓的外面,那麼說明點k也一定在前k個點(包括i,j)的最小覆蓋圓邊界上,我們不需要再進一步確定這個圓了(因為三個點能確定乙個圓!),直接求出這三點共圓,否則前k個點(包括i,j)的最小覆蓋圓與前k-1個點(包括i,j)的最小覆蓋圓是一樣的,則不需要更新。
時間複雜度:o(n)
空間複雜度:o(n)
複雜度證明:空間複雜度顯然,下面來證時間複雜度
首先,因為我們已經將點打亂順序,所以我們可以認為點是隨機生成的
我們知道,當點完全隨機時,第i個點在前i-1個點的最小覆蓋圓外的機率是3/i
證明:我們先隨機生成i個點,求出他們的最小覆蓋圓,我們可以認為這個圓是由現在在邊界上的那三個點來確定的,也就是說當隨機生成的最後乙個點不是那三個點時,新生成的點就在圓內,否則在圓外,所以第i個點在前i-1個點的最小覆蓋圓外的概率只有3/i
所以o(
②)=∑
i=1i
≤n(i
−3i∗
o(1)
+3i∗
o(④)
) 而
o(④)
=∑i=
1i≤n
(i−3
i∗o(
1)+3
i∗o(
⑥))
易知o(
⑥)=o
(n)
所以可以推出,這個做法是線性的
注意事項:
以上時間複雜度的證明全部基於點的排列隨機,如果點的排列不隨機,那麼時間複雜度將有可能達到o(
n3)
所以最小圓覆蓋演算法只能在o(n)時間內求出n的點的最小覆蓋圓,而不能在o(n)的時間內求出所有的前i個點的最小覆蓋圓
下面是一段給定n個點求最小覆蓋圓圓心及半徑的**(bzoj1336/1337)
#include
#include
#include
#include
#include
#define n 100010
using namespace std;
struct nodeb[n];
node o;
double r;
double s
qr(double x)
double dis(node x,node y)
bool incircle(node x)
node solve(double a,double b,double c,double d,double e,double f);}
int main()}}
printf("%.10lf\n%.10lf %.10lf",r,o.x,o.y);
}
最小圓覆蓋
最小圓覆蓋。神奇的隨機演算法。當點以隨機的順序加入時期望複雜度是線性的。algorithm a 令ci表示為前i個點的最小覆蓋圓。當加入新點pi時如果pi不在ci 1裡那麼pi必定在ci的邊界上。b 再從新考慮這樣乙個問題,ci為前i個點最小覆蓋圓且p在ci的的邊界上!同理加入新點pi時如果p i不...
最小圓覆蓋
最小圓覆蓋問題 在乙個平面上,給出 n 個點,求包圍這些點的最小圓,輸出圓心及半徑。分析雖然可以用模擬退火或者三分套三分,這裡只講隨機增量法,隨機增量法是一種確定性演算法,隨機意義下均攤複雜度 o n 而且可以達到很高的精度 可達到 10 10 量級 有事實 如果點 p 不在集合 s 的最小圓覆蓋內...
最小圓覆蓋
本來不想學的 於是今天就碰到一道大裸題 例題 bzoj2823 求最小圓覆蓋n個點。偽 如下 把所有點隨機化,設為 x 1 y 1 x n y n 開始把圓心設為x 1 半徑設為0 for i 2ton 如果i號點在當前圓內則跳過 那麼i號點就在圓周上 把1號點和i號點作為直徑作乙個圓 for j ...