kZjPBD.jpg

【BZOJ 2618】 2618: [Cqoi2006]凸多边形 (半平面交)

2618: [Cqoi2006]凸多边形

Description

逆时针给出n个凸多边形的顶点坐标,求它们交的面积。例如n=2时,两个凸多边形如下图:

则相交部分的面积为5.233。

Input

第一行有一个整数n,表示凸多边形的个数,以下依次描述各个多边形。第i个多边形的第一行包含一个整数mi,表示多边形的边数,以下mi行每行两个整数,逆时针给出各个顶点的坐标。

Output

    输出文件仅包含一个实数,表示相交部分的面积,保留三位小数。

Sample Input

2
6
-2 0
-1 -2
1 -2
2 0
1 2
-1 2
4
0 -3
1 -1
2 2
-1 0

Sample Output

5.233

HINT

100%的数据满足:2<=n<=10,3<=mi<=50,每维坐标为[-1000,1000]内的整数

 

solution:

转化为很多直线的半平面交

code:

 

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<cmath>
  7 using namespace std;
  8 #define Maxn 1100
  9 
 10 struct P
 11 {
 12     double x,y;
 13     P()
 14     {
 15         x=y=0;
 16     }
 17     P(double x,double y):x(x),y(y) {}
 18     friend P operator - (P x,P y)
 19     {
 20         return P(x.x-y.x,x.y-y.y);
 21     }
 22     friend P operator + (P x,P y)
 23     {
 24         return P(x.x+y.x,x.y+y.y);
 25     }
 26     friend P operator * (P x,double y)
 27     {
 28         return P(x.x*y,x.y*y);
 29     }
 30     friend double operator * (P x,P y)
 31     {
 32         return x.x*y.y-x.y*y.x;
 33     }
 34     friend double operator / (P x,P y)
 35     {
 36         return x.x*y.x+x.y*y.y;
 37     }
 38 } a[Maxn];
 39 struct L
 40 {
 41     P a,b,v;
 42     
 43     // v为方向向量
 44     
 45     double slop;
 46 
 47     friend bool operator < (L a,L b)
 48     {
 49         return (a.slop!=b.slop)?(a.slop<b.slop):a.v*(b.b-a.a)>0;
 50         // 极角相同,保留相对在左侧的
 51     }
 52     friend P inter(L b,L a)
 53     {
 54         P nw=b.a-a.a;
 55         double tt=(nw*a.v)/(a.v*b.v);
 56         return b.a+b.v*tt;
 57         // 求两个直线的交点 
 58     }
 59 
 60     friend bool jud(P x,L c)
 61     {
 62         return c.v*(x-c.a)<0;
 63     }
 64 
 65 } l[Maxn],q[Maxn];
 66 int cnt,tot;
 67 
 68 void ffind()
 69 {
 70     for(int i=1; i<=cnt; i++) l[i].v=l[i].b-l[i].a,l[i].slop=atan2(l[i].v.y,l[i].v.x);
 71     sort(l+1,l+1+cnt);
 72     int L=1,R=0;
 73     tot=0;
 74     for(int i=1; i<=cnt; i++)
 75     {
 76         if(l[i].slop!=l[i-1].slop) tot++;
 77         l[tot]=l[i];
 78     }
 79     cnt=tot;
 80     tot=0;
 81     q[++R]=l[1];
 82     q[++R]=l[2];
 83     for(int i=3; i<=cnt; i++)
 84     {
 85         while(L<R&&jud(inter(q[R-1],q[R]),l[i])) R--;
 86         while(L<R&&jud(inter(q[L+1],q[L]),l[i])) L++;
 87         q[++R]=l[i];
 88     }
 89     while(L<R&&jud(inter(q[R-1],q[R]),q[L])) R--;
 90     while(L<R&&jud(inter(q[L+1],q[L]),q[R])) L++;
 91     q[R+1]=q[L];
 92     for(int i=L; i<=R; i++) a[++tot]=inter(q[i],q[i+1]);
 93 }
 94 
 95 void init()
 96 {
 97     int n;
 98     scanf("%d",&n);
 99     cnt=0;
100     for(int i=1; i<=n; i++)
101     {
102         int m;
103         scanf("%d",&m);
104         P ft,now,nw;
105         scanf("%lf%lf",&ft.x,&ft.y);
106         now=ft;
107         for(int j=2; j<=m; j++)
108         {
109             scanf("%lf%lf",&nw.x,&nw.y);
110             l[++cnt].b=nw,l[cnt].a=now;
111             now=nw;
112         }
113         l[++cnt].a=now;
114         l[cnt].b=ft;
115     }
116     // 必须保证是逆时针输入点
117 }
118 
119 void get_area()// 任意多边形的面积
120 {
121     double ans=0;
122     for(int i=1; i<tot; i++) ans+=a[i]*a[i+1];
123     ans+=a[tot]*a[1];
124     if(tot<3) ans=0;
125     printf("%.3lf\n",ans/2);
126 }
127 
128 int main()
129 {
130     init();
131     ffind();
132     get_area();
133     return 0;
134 
135 }

 

posted @ 2019-07-02 21:16  Through_The_Night  阅读(134)  评论(0编辑  收藏  举报