【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
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 }