BZOJ 1337: 最小圓覆蓋1336: [Balkan2002]Alien最小圓覆蓋(隨機增量法)


今天才知道有一種東西叫隨機增量法就來學了= =

挺神奇的= =

A.令ci為包括前i個點的最小圓,若第i+1個點無法被ci覆蓋,則第i+1個點一定在ci+1上

B.令ci為包括前i個點的最小圓且p在邊上,若第i+1個點無法被ci覆蓋,則第i+1個點與點p一定在ci+1上

C.令ci為包括前i個點的最小圓且p,q在邊上,若第i+1個點無法被ci覆蓋,則第i+1個點與點p,q一定在ci+1上

這樣就確定一個圓了

這樣看上去是O(n^3)的,但是注意這個名字= =隨機,說明我們能通過隨機使其降到O(n)

首先C顯然是線性

那么B-》c呢?對於一個點pi,在院內的概率是(i-1)/i在圓外的概率是1/i(因為這些點是隨機的= =) 所以加入的復雜度為(i-1)/i*O(1)+1/i*O(i);

A-》B同理,因此該算法的時間復雜度為線性的

隨機化多么神奇啊= =

c++可以直接random_shuffle(STL多么神奇!!!)來隨機化數組

CODE:

#include<cstdio>

#include<iostream>

#include<cstring>

#include<algorithm>

#include<cmath>

using namespace std;

#define sqr(x) ((x)*(x))

#define fi first

#define se second

#define maxn 100100

typedef pair<double,double> ii;

ii a[maxn],cir;

double r;

double dis(ii x,ii y) {

return sqrt(sqr(x.fi-y.fi)+sqr(x.se-y.se));

}

ii getcir(ii x,ii y,ii z){

double a=sqr(x.fi)-sqr(y.fi)+sqr(x.se)-sqr(y.se),

  b=sqr(x.fi)-sqr(z.fi)+sqr(x.se)-sqr(z.se),

  c=2*(x.se-z.se)*(x.fi-y.fi)-2*(x.se-y.se)*(x.fi-z.fi);

return ii((a*(x.se-z.se)-b*(x.se-y.se))/c,

(a*(x.fi-z.fi)-b*(x.fi-y.fi))/(-c));

}

#define exp 1e-10

int cmp(double x) {

if (x<-exp) return -1;

if (x>exp) return 1;

return 0;

}

int n;

int main(){

scanf("%d",&n);

for (int i=1;i<=n;i++) scanf("%lf%lf",&a[i].fi,&a[i].se);

random_shuffle(a+1,a+1+n);

cir=a[1],r=0;

for (int i=1;i<=n;i++) {

if (cmp(dis(cir,a[i])-r)<=0) continue;

cir=a[i],r=0;

for (int j=1;j<i;j++) {

if (cmp(dis(cir,a[j])-r)<=0) continue;

cir.fi=(a[i].fi+a[j].fi)/2,cir.se=(a[i].se+a[j].se)/2;

r=dis(cir,a[j]);

for (int k=1;k<j;k++) {

if (cmp(dis(cir,a[k])-r)<=0) continue;

cir=getcir(a[i],a[j],a[k]);

r=dis(cir,a[i]);

}

}

}

printf("%lf\n%lf %lf\n",r,cir.fi,cir.se);

return 0;

}



注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com