給定平面上的n求解上述問題便是welnn個點,求乙個最小的圓使得所有的點都落在圓內。
zl
welzl
welz
l演算法的作用。其期望複雜度可以達到o(n
)o(n)
o(n)。wel
zl
welzl
welz
l演算法的正確性基於乙個定理:
定理:對於平面上任意n
nn個點,在其最小覆蓋圓外取第n+1
n+1n+
1個點。那麼第n+1
n+1n+
1個點一定在這n+1
n+1n+
1個點的最小覆蓋圓上。
有了這個定理,就可以進行wel
zl
welzl
welz
l演算法了。先取3個點建立乙個圓(不共線的三個點能確定乙個圓,如果共線就取距離最遠的兩個點作為直徑建立圓),然後遍歷剩下的所有點,對於乙個遍歷到的點kkk:
寫成**就是:
// a 存放需要求最小圓覆蓋的所有點,n 為點的數量
// radius 為圓半徑,center為圓心,都是全域性變數
// point_in 函式判斷乙個點是否在最小覆蓋圓內
// circle_center 函式有兩個過載,乙個用兩個點確定圓,乙個用三個點確定圓
// dist 函式計算距離
void
min_circle_cover
(point a,
int n)}}
}}}}
關於這個期望線性複雜度,我並不會證明。
只要呼叫min
_cir
cle_
cove
rmin\_circle\_cover
min_ci
rcle
_cov
er之前呼叫ran
dom_
shuf
fl
erandom\_shuffle
random
_shu
ffle
隨機排列一下,就可以保證期望線性複雜度。
這裡給乙個完整**(洛谷p1742的ac**):
#include
using
namespace std;
const
int maxn =
1e5+10;
const
double eps =
1e-8
;int
cmp(
double x)
struct point
point
(double a,
double b):x
(a),
y(b)
friend point operator-(
const point& a,
const point& b)
double
norm()
}p[maxn]
;double
dist
(const point& a,
const point& b)
void
circle_center
(point p0, point p1, point& cp)
void
circle_center
(point p0, point p1, point p2, point& cp)
double radius; point center;
bool
point_in
(const point& p)
void
min_circle_cover
(point a,
int n)}}
}int
main()
random_shuffle
(p, p + n)
;min_circle_cover
(p, n)
;printf
("%.10lf\n%.10lf %.10lf"
, radius, center.x, center.y)
;return0;
}
例題:
洛谷p1742 最小圓覆蓋 [傳送門]
洛谷p2533 [ahoi2012]訊號塔 [傳送門]
最小圓覆蓋演算法
演算法目的 演算法步驟 首先現將所有點隨機排列 按順序把點乙個乙個的加入 一步一步的求前i個點的最小覆蓋圓 每加入乙個點就進入 如果發現當前i號點在當前的最小圓的外面,那麼說明點i一定在前i個點的最小覆蓋圓邊界上,我們轉到 來進一步確定這個圓,否則前i個點的最小覆蓋圓與前i 1個點的最小覆蓋圓是一樣...
最小圓覆蓋
最小圓覆蓋。神奇的隨機演算法。當點以隨機的順序加入時期望複雜度是線性的。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 的最小圓覆蓋內...