CF613A:Peter and Snow Blower

用一个圆心在(x,y)的圆环覆盖一个n边形,顺或逆时针给出n边形所有顶点,求圆环最小面积。

卡了好久,各种傻逼错误。。

题目就是让我们固定一大一小两个边界圆,我们来看看这两个圆满足什么条件。

首先外面的那个圆肯定是经过n边形的某个顶点,所以外圆半径就是最大的点距。

其次内圆呢,可能经过一个点,也可能与某条边相切,但注意,这里的线是线段不是直线!

所以可能会出现最后的内圆和某条“直线”相交而与其对应的线段没有交点。例如:

上图中内圆与四条“直线”都相交,但与“线段”只有一个交点。

为了判断内圆,我用了最粗暴的方法--二分,计算与当前半径的圆相交的“直线“的两个交点是否在“线段”上,用横坐标或纵坐标判断。

Trick:

如果是用y=kx+b就会wa,因为平面上不是所有的直线都能这么表示,要用一般式Ax+By+C=0。

计算圆与直线相交情况时记得分B是否为0的情况。所有计算过程中记得判断除0情况。

精度。二分时在精度那里要注意R-eps或者L+eps,不然可能tle。

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<algorithm>
  4 #include<cstdlib>
  5 #include<cstring>
  6 #include<cmath>
  7 //#include<iostream>
  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<n;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 }
View Code

 

posted @ 2017-07-17 10:54  Blue233333  阅读(180)  评论(0编辑  收藏  举报