题目链接
http://www.lydsy.com/JudgeOnline/problem.php?id=2618
思路
实际上就是很多条直线求半平面交的面积,这是很显然的。
所以直接用半平面交+三角剖分模板就能水过。
代码
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <cmath>
#define MAXN 10000
#define EPS 1e-6
using namespace std;
int dcmp(double a)
{
if(fabs(a)<EPS) return 0;
if(a>EPS) return 1;
return -1;
}
struct Point
{
double x,y;
Point(){}
Point(double _x,double _y):x(_x),y(_y){}
}points[MAXN],polygon[MAXN];
int n=0,sizeOfPoly=0;
Point operator-(Point a,Point b)
{
return Point(a.x-b.x,a.y-b.y);
}
Point operator+(Point a,Point b)
{
return Point(a.x+b.x,a.y+b.y);
}
Point operator*(Point a,double b)
{
return Point(a.x*b,a.y*b);
}
Point operator/(Point a,double b)
{
return Point(a.x/b,a.y/b);
}
double operator*(Point a,Point b)
{
return a.x*b.x+a.y*b.y;
}
double cross(Point a,Point b)
{
return a.x*b.y-a.y*b.x;
}
struct Line
{
Point st,ed;
double ang;
Line(){}
Line(Point _st,Point _ed):st(_st),ed(_ed)
{
ang=atan2((st-ed).y,(st-ed).x);
}
}lines[MAXN],q[MAXN];
int top=0,h=1,t=0;
Point getLineIntersec(Line a,Line b)
{
double x=cross(a.ed-a.st,b.ed-b.st); //!!!!!
double y=cross(b.st-a.st,a.ed-a.st);
return b.st+(b.ed-b.st)*y/x;
}
bool cmp(Line a,Line b) //按照极角升序排序
{
if(!dcmp(a.ang-b.ang)) return dcmp(cross(a.ed-a.st,b.ed-a.st))>0;
return dcmp(a.ang-b.ang)<0;
}
bool onLeft(Line a,Point b)
{
return dcmp(cross(b-a.st,a.ed-a.st))<=0;
}
void HalfPanelIntersec() //半平面交
{
int tot=0;
sort(lines+1,lines+n+1,cmp);
for(int i=1;i<=n;i++) //去掉极角相同的直线
{
if(dcmp(lines[i].ang-lines[i-1].ang)) tot++;
lines[tot]=lines[i];
}
q[++t]=lines[1],q[++t]=lines[2];
for(int i=1;i<=tot;i++)
{
while(h<t&&!onLeft(lines[i],getLineIntersec(q[t-1],q[t]))) t--;
if(h<t&&!dcmp(fabs(cross(q[t].ed-q[t].st,q[t-1].ed-q[t-1].st))))
{
if(onLeft(q[t],lines[i].st)) //i与队尾直线平行且方向相同,则需要保留靠近半平面交内部的那条
q[t]=lines[i];
}
else q[++t]=lines[i];
}
while(t-h>=2&&!onLeft(q[t],getLineIntersec(q[h],q[h+1]))) h++;
while(t-h>=2&&!onLeft(q[h],getLineIntersec(q[t],q[t-1]))) t--;
for(int i=h;i<t;i++)
polygon[++sizeOfPoly]=getLineIntersec(q[i],q[i+1]);
polygon[++sizeOfPoly]=getLineIntersec(q[t],q[h]);
}
double getSqrOfPolygon()
{
double sqr=0;
if(sizeOfPoly<=2) return 0;
polygon[++sizeOfPoly]=polygon[1];
for(int i=1;i<=sizeOfPoly;i++)
sqr+=cross(polygon[i],polygon[i+1]);
return fabs(sqr)/2;
}
int main()
{
int m;
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int cnt=0;
scanf("%d",&cnt);
Point p1,p2,tmp;
scanf("%lf%lf",&p1.x,&p1.y);
tmp=p1;
for(int j=2;j<=cnt;j++)
{
scanf("%lf%lf",&p2.x,&p2.y);
lines[++n]=Line(p1,p2);
p1=p2;
}
lines[++n]=Line(p1,tmp);
}
HalfPanelIntersec();
printf("%.3lf\n",getSqrOfPolygon());
return 0;
}