用一个圆心在(x,y)的圆环覆盖一个n边形,顺或逆时针给出n边形所有顶点,求圆环最小面积。
卡了好久,各种傻逼错误。。
题目就是让我们固定一大一小两个边界圆,我们来看看这两个圆满足什么条件。
首先外面的那个圆肯定是经过n边形的某个顶点,所以外圆半径就是最大的点距。
其次内圆呢,可能经过一个点,也可能与某条边相切,但注意,这里的线是线段不是直线!
所以可能会出现最后的内圆和某条“直线”相交而与其对应的线段没有交点。例如:
上图中内圆与四条“直线”都相交,但与“线段”只有一个交点。
为了判断内圆,我用了最粗暴的方法--二分,计算与当前半径的圆相交的“直线“的两个交点是否在“线段”上,用横坐标或纵坐标判断。
Trick:
如果是用y=kx+b就会wa,因为平面上不是所有的直线都能这么表示,要用一般式Ax+By+C=0。
计算圆与直线相交情况时记得分B是否为0的情况。所有计算过程中记得判断除0情况。
精度。二分时在精度那里要注意R-eps或者L+eps,不然可能tle。
1 #include2 #include 3 #include 4 #include 5 #include 6 #include 7 //#include 8 using namespace std; 9 10 int n; 11 #define maxn 100011 12 struct Point 13 { 14 double x,y; 15 }a[maxn],P; 16 struct Line 17 { 18 double a,b,c,dis; 19 }l[maxn]; 20 const double eps=1e-10,pi=3.1415926535897932384626434; 21 void do_line(int id,double x1,double y1,double x2,double y2) 22 { 23 if (x1==x2) 24 { 25 l[id].a=1; 26 l[id].b=0; 27 l[id].c=-x1; 28 } 29 else if (y1==y2) 30 { 31 l[id].a=0; 32 l[id].b=1; 33 l[id].c=-y1; 34 } 35 else if (x2*y1==x1*y2) 36 { 37 l[id].c=0; 38 l[id].a=233333; 39 if (y1) l[id].b=-x1/y1*l[id].a; 40 else l[id].b=-x2/y2*l[id].a; 41 } 42 else 43 { 44 l[id].c=100000; 45 l[id].a=l[id].c*(y2-y1)/(x2*y1-x1*y2); 46 l[id].b=l[id].c*(x2-x1)/(y2*x1-y1*x2); 47 } 48 l[id].dis=abs(l[id].a*P.x+l[id].b*P.y+l[id].c)/sqrt(l[id].a*l[id].a+l[id].b*l[id].b); 49 } 50 double ppdissqr(double x1,double y1,double x2,double y2) 51 { 52 return (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1); 53 } 54 bool judge(double x) 55 { 56 for (int i=1;i<=n;i++) 57 if (l[i].dis-x<=-eps) 58 { 59 double A=l[i].a,B=l[i].b,C=l[i].c; 60 if (B) 61 { 62 double delta=((A/B)*(A/B)+1)*x*x-((A*P.x+C)/B+P.y)*((A*P.x+C)/B+P.y), 63 x1=(-2*(A/B*(C/B+P.y)-P.x)+sqrt(delta))/(2*(1+(A/B)*(A/B))), 64 x2=(-2*(A/B*(C/B+P.y)-P.x)-sqrt(delta))/(2*(1+(A/B)*(A/B))); 65 double p=a[i].x,q=a[i+1].x; 66 if (i==n) q=a[1].x; 67 if (p>q) swap(p,q); 68 if ((x1>=p && x1<=q) 69 || (x2>=p && x2<=q)) 70 return 0; 71 } 72 else 73 { 74 double y1=P.y+sqrt(x*x-(-C/A-P.x)*(-C/A-P.x)), 75 y2=P.y-sqrt(x*x-(-C/A-P.x)*(-C/A-P.x)); 76 double p=a[i].y,q=a[i+1].y; 77 if (i==n) q=a[1].y; 78 if (p>q) swap(p,q); 79 if ((y1>=p && y1<=q) 80 || (y2>=p && y2<=q)) 81 return 0; 82 } 83 } 84 return 1; 85 } 86 int main() 87 { 88 scanf("%d%lf%lf",&n,&P.x,&P.y); 89 for (int i=1;i<=n;i++) scanf("%lf%lf",&a[i].x,&a[i].y); 90 for (int i=1;i ) 91 do_line(i,a[i].x,a[i].y,a[i+1].x,a[i+1].y); 92 do_line(n,a[n].x,a[n].y,a[1].x,a[1].y); 93 double f1=0.0,r2,L=0.0,R; 94 for (int i=1;i<=n;i++) 95 f1=max(f1,ppdissqr(a[i].x,a[i].y,P.x,P.y)); 96 R=sqrt(f1); 97 for (int i=1;i<=n;i++) 98 R=min(R,sqrt(ppdissqr(a[i].x,a[i].y,P.x,P.y))); 99 while (R-L>eps) 100 { 101 double mid=(L+R+eps)/2; 102 if (judge(mid)) L=mid; 103 else R=mid-eps; 104 } 105 r2=(L+R)/2; 106 printf("%.10lf\n",pi*(f1-r2*r2)); 107 return 0; 108 }