最近翔哥上課講計算幾何這個神奇玩意。然后一堆新高一創新班的都特High,然后我們一堆初二的ZZ全程懵逼。
但是剛開始講的這個東西還是令人耳目一新的。
何為最小覆蓋圓,顧名思義,就是覆蓋平面內所有點的最小的圓。
原來隨機化算法這么強勁?好了我們來看這個算法——隨機增量法
一看名字就知道,先要把輸入的點打亂,使其隨機化。玄學
然后就是從第一個點開始枚舉點\(i\),如果當前的枚舉的點在圓內部,就繼續不用管(顯然的)。否則就以該點為圓心半徑為\(0\)開始枚舉\(j(1\le j < i)\) 。
如果\(j\)在當前圓的外面就取點\(i\)和點\(j\)的中點為圓心,距離的一半為半徑(兩點的最小覆蓋圓)。以這個圓再枚舉\(k(1\le k<j)\),然后如果點\(k\)在圓外(這和上面的都是一樣的)。就以\(i,j,k\)三點在計算最小覆蓋圓。
而這個最小覆蓋圓就是前\(i\)個點的最小覆蓋圓。
然后最大的問題就在於這個已知三點求圓的圓心及半徑的過程了。這里給出弱弱的解析幾何方法計算幾何我不會啊
我們要先知道一個關於圓的公式:
\(x^2+y^2=r^2\)
然后我們設圓心的坐標為\((x_0,y_0)\)然后就可以列一個三元二次方程解出\(x_0,y_0\)的值。
但是具體的解法太過技術性,找到一篇超級詳細的解法。請仔細參閱。
然后就是堅定不移的相信自己是歐皇然后不被卡精度
但是這個復雜度就是玄學\(O(n)\)(具體證明參考dalao‘s blog)
板子(就是那個min_cover_circleEnglish level is too low)
inline DB power(DB x)
{
return x*x;
}
inline DB dis(node a,node b)
{
return sqrt(power(a.x-b.x)+power(a.y-b.y));
}
inline bool in_circle(node a)
return dis(a,O)<=r?1:0;
}
inline void calc(DB a,DB b,DB c,DB d,DB e,DB f)
{
O.x=(b*f-d*e)/(b*c-a*d);
O.y=(c*e-a*f)/(b*c-a*d);
}
inline void min_cover_circle(void)
{
register int i,j,k;
random_shuffle(a+1,a+n+1);
for (i=1;i<=n;++i)
if (!in_circle(a[i]))
{
O=a[i]; r=0;
for (j=1;j<i;++j)
if (!in_circle(a[j]))
{
O.x=(a[i].x+a[j].x)/2.0; O.y=(a[i].y+a[j].y)/2.0; r=dis(a[i],O);
for (k=1;k<j;++k)
if (!in_circle(a[k])) calc(a[i].x-a[j].x,a[i].y-a[j].y,a[i].x-a[k].x,a[i].y-a[k].y,
((power(a[i].x)-power(a[j].x))-(power(a[j].y)-power(a[i].y)))/2.0,
((power(a[i].x)-power(a[k].x))-(power(a[k].y)-power(a[i].y)))/2.0),r=dis(a[i],O);
}
}
}
最后求出的O就是原點,r是半徑。
然后我們來看一些板子題:
這題的數據范圍很小。盡管我們\(O(n^3)\)大暴力是可以過的,但是對於新的算法還是要練習一下。
BZOJ的數據強度比較高,但那個神奇精度問題實在是。。。。。。
樣例保留兩位,實際上要保留10位,題目也沒講。這是讓我們猜數據范圍么?
Luogu P1742 最小圓覆蓋&&Luogu P2533 [AHOI2012]信號塔
和BZOJ的基本就是重題,但是多虧洛谷才搞懂了數據范圍。
莫名弄了一個玄學省選算法。還是挺棒的。