最小圆覆盖(随机增量||模拟退火)
最小圆覆盖
https://www.lydsy.com/JudgeOnline/problem.php?id=1337
Submit: 1464 Solved: 737
[Submit][Status][Discuss]
Description
给出平面上N个点,N<=10^5.请求出一个半径最小的圆覆盖住所有的点
Input
第一行给出数字N,现在N行,每行两个实数x,y表示其坐标.
Output
输出最小半径,输出保留三位小数.
Sample Input
4
1 0
0 1
0 -1
-1 0
1 0
0 1
0 -1
-1 0
Sample Output
1.000
ac1() 模拟退火,ac2()随机增量法
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<vector> 5 #include<cmath> 6 #include<algorithm> 7 using namespace std; 8 const double eps=1e-8; 9 const double INF=1e20; 10 const double PI=acos(-1.0); 11 12 13 ///pick定理:面积=内部格点数+(边上格点数/2)-1 14 15 int sgn(double x){ 16 if(fabs(x)<eps) return 0; 17 if(x<0) return -1; 18 else return 1; 19 } 20 21 inline double sqr(double x){return x*x;} 22 inline double hypot(double a,double b){return sqrt(a*a+b*b);} 23 struct Point{ 24 double x,y; 25 Point(){} 26 Point(double _x,double _y){ 27 x=_x; 28 y=_y; 29 } 30 void input(){ 31 scanf("%lf %lf",&x,&y); 32 } 33 Point operator - (const Point &b)const{ 34 return Point(x-b.x,y-b.y); 35 } 36 //叉积 37 double operator ^ (const Point &b)const{ 38 return x*b.y-y*b.x; 39 } 40 //点积 41 double operator * (const Point &b)const{ 42 return x*b.x+y*b.y; 43 } 44 //返回长度 45 double len(){ 46 return hypot(x,y); 47 } 48 //返回两点的距离 49 double distance(Point p){ 50 return hypot(x-p.x,y-p.y); 51 } 52 Point operator + (const Point &b)const{ 53 return Point(x+b.x,y+b.y); 54 } 55 Point operator * (const double &k)const{ 56 return Point(x*k,y*k); 57 } 58 Point operator / (const double &k)const{ 59 return Point(x/k,y/k); 60 } 61 62 //逆时针转90度 63 Point rotleft(){ 64 return Point(-y,x); 65 } 66 }; 67 68 struct Line{ 69 Point s,e; 70 Line(){} 71 Line(Point _s,Point _e){ 72 s=_s; 73 e=_e; 74 } 75 //根据一个点和倾斜角angle确定直线,0<=angle<pi 76 Line(Point p,double angle){ 77 s=p; 78 if(sgn(angle-PI/2)==0){ 79 e=(s+Point(0,1)); 80 } 81 else{ 82 e=(s+Point(1,tan(angle))); 83 } 84 } 85 //ax+by+c=0; 86 Line(double a,double b,double c){ 87 if(sgn(a)==0){ 88 s=Point(0,-c/b); 89 e=Point(1,-c/b); 90 } 91 else if(sgn(b)==0){ 92 s=Point(-c/a,0); 93 e=Point(-c/a,1); 94 } 95 else{ 96 s=Point(0,-c/b); 97 e=Point(1,(-c-a)/b); 98 } 99 } 100 101 //求两直线的交点 102 //要保证两直线不平行或重合 103 Point crosspoint(Line v){ 104 double a1=(v.e-v.s)^(s-v.s); 105 double a2=(v.e-v.s)^(e-v.s); 106 return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1)); 107 } 108 }; 109 110 struct circle{ 111 Point p; 112 double r; 113 circle(){} 114 circle(Point _p,double _r){ 115 p=_p; 116 r=_r; 117 } 118 119 circle(double x,double y,double _r){ 120 p=Point(x,y); 121 r=_r; 122 } 123 124 circle(Point a,Point b,Point c){///三角形的外接圆 125 Line u=Line((a+b)/2,((a+b)/2)+((b-a).rotleft())); 126 Line v=Line((b+c)/2,((b+c)/2)+((c-b).rotleft())); 127 p=u.crosspoint(v); 128 r=p.distance(a); 129 } 130 131 132 }; 133 134 Point p[100005]; 135 int n; 136 137 void ac2(){ 138 random_shuffle(p+1,p+n+1); 139 circle c(p[1],0); 140 for(int i=1;i<=n;i++){ 141 if(sgn((c.p-p[i]).len()-c.r)>0){ 142 c.p=p[i],c.r=0; 143 for(int j=1;j<i;j++){ 144 if(sgn((c.p-p[j]).len()-c.r)>0){ 145 c.p=(p[i]+p[j])/2; 146 c.r=(c.p-p[j]).len(); 147 for(int k=1;k<j;k++){ 148 if(sgn((c.p-p[k]).len()-c.r)>0){ 149 c=circle(p[i],p[j],p[k]); 150 } 151 } 152 } 153 } 154 } 155 } 156 printf("%f\n%f %f\n",c.r,c.p.x,c.p.y); 157 } 158 159 double dist(Point a,Point b){ 160 return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); 161 } 162 163 void ac1(){ 164 165 double ans=1e99; 166 Point tmp; 167 tmp.x=tmp.y=0; 168 int s=1; 169 double step=10000; 170 double esp=0.000001; 171 while(step>esp){ 172 for(int i=1;i<=n;i++){ 173 if(dist(tmp,p[s])<dist(tmp,p[i])) s=i; 174 } 175 double Dist=dist(tmp,p[s]); 176 ans=min(ans,Dist); 177 tmp.x+=(p[s].x-tmp.x)/Dist*step; 178 tmp.y+=(p[s].y-tmp.y)/Dist*step; 179 step*=0.98; 180 } 181 printf("%.3f\n",ans); 182 } 183 int main(){ 184 185 scanf("%d",&n); 186 for(int i=1;i<=n;i++){ 187 p[i].input(); 188 } 189 ac1(); 190 191 return 0; 192 }
posted on 2019-05-09 21:59 Fighting_sh 阅读(440) 评论(0) 编辑 收藏 举报