Welzl演算法求最小圓覆蓋

2021-10-21 11:36:53 字數 2255 閱讀 2034

給定平面上的n

nn個點,求乙個最小的圓使得所有的點都落在圓內。

求解上述問題便是wel

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 的最小圓覆蓋內...