本來不想學的…於是今天就碰到一道大裸題…
例題:bzoj2823 求最小圓覆蓋n個點。
偽**如下:
把所有點隨機化,設為(x[1],y[1])...(x[n],y[n])
開始把圓心設為x[
1],半徑設為0
for i=2ton
如果i號點在當前圓內則跳過
//那麼i號點就在圓周上
把1號點和i號點作為直徑作乙個圓
for j=1
to i-1
如果j號點在當前圓內則跳過
考慮以j號點和i號點作為直徑作乙個圓
for k=1
to j-1
如果k號點在當前圓內則跳過
以i,j,k三點組成的三角形的外心作為新圓心
如果i,j,k三點共線就取ij、ik、jk連線最長的那條作為直徑作為新圓
據說期望複雜度是o(n)的。
細節還是比較多的。
首先共線叉積是比較容易判的。如果叉積為0那麼就共線。
那麼三角形的外心怎麼求呢?
如果有3個點,a(x1,y1),b(x2,y2),c(x3,y3)。
ab解析式:(y2-y1)x+(x1-x2)y+x2*y1-x1*y2=0
ab中點:((x1+x2)/2,(y1+y2)/2)
那麼ab中垂線解析式就是(y1-y2)x+(x1-x2)y+一些常數,把ab中點的座標帶進去減一下就行了。
然後我們求一下ab和ac中垂線的交點。
兩條直線
ax+by=c dx+ey=f
aex+bey=ce dbx+eby=fb
x=(fb-ce)/(ae-db)
同理adx+bdy=cd adx+aey=af
y=(af-cd)/(ae-bd)
當然如果ae=bd就共線。
所以就解決啦。
#include #include#include
#include
#include
#include
#include
#include
#include
#include
using
namespace
std;
intn;
#define sz 2333333typedef
double
db;struct
pnt pnt(db a,db b)
}ps[sz];
pnt
operator - (pnt a,pnt b)
db operator * (pnt a,pnt b)
db pf(db x)
db dis(pnt a,pnt b)
pnt mid(pnt a,pnt b)
struct
lne lne(db x,db y,db z)
};pnt
operator *(lne a,lne b)
lne zcx(pnt a,pnt b)
pnt wx(pnt a,pnt b,pnt c)
db eps=1e-6
;pnt np(pnt a,pnt b,pnt c)
return
wx(a,b,c);
}db gr(pnt o,pnt a,pnt b,pnt c)
intmain()}}
printf(
"%.2lf %.2lf %.2lf\n
",yx.x,yx.y,r);
}
最小圓覆蓋
最小圓覆蓋。神奇的隨機演算法。當點以隨機的順序加入時期望複雜度是線性的。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 的最小圓覆蓋內...
最小圓覆蓋
1.首先將所有點隨機排列 2.按順序依次將點加入已經建好的圓中,每新增乙個點就進入步驟3 3.如果點i在當前最小圓的外部,那麼說明點i一定在前i個點構成的最小圓的邊界上 因為要保證最小圓 進入步驟4處理 如果點i在當前最小圓的內部,則返回步驟2 4.此時已經確定點i一定在前i個點所構成的最小圓的邊界...