题目链接:https://vjudge.net/problem/POJ-1279
半平面交学习:点击查看
题解:求内核面积,半平面交,存模板
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const double eps=1e-8;
int sgn(double x)
{
if(fabs(x)<eps)return 0;
if(x<0)return -1;
return 1;
}
struct Point{
double x,y;
Point(){
}
Point(double x_,double y_)
{
x=x_;
y=y_;
}
Point operator -(const Point &b)const
{
return Point(x-b.x,y-b.y);
}
double operator ^(const Point &b)const
{
return x*b.y-y*b.x;
}
double operator *(const Point &b)const
{
return x*b.x+y*b.y;
}
};
struct Line{
Point s,e;
double k;
Line(){
}
Line(Point s_,Point e_)
{
s=s_;
e=e_;
k=atan2(e.y-s.y,e.x-s.x);
}
Point operator &(const Line &b)const
{
Point res=s;
double t=((s-b.s)^(b.s-b.e))/((s-e)^(b.s-b.e));
res.x += (e.x-s.x)*t;
res.y += (e.y-s.y)*t;
return res;
}
};
bool HPIcmp(Line a,Line b)
{
if(fabs(a.k-b.k)>eps)return a.k<b.k;
else return ((a.s-b.s)^(b.e-b.s))<0;
}
Line Q[1510];
void HPI(Line line[],int n,Point res[],int &resn)
{
int tot=n;
sort(line,line+n,HPIcmp);
tot=1;
for(int i=1;i<n;i++) // 去掉右边的线段,保留左边的线段。
{
if(fabs(line[i].k-line[i-1].k)>eps)
line[tot++]=line[i];
}
int head=0,tail=1;
Q[0]=line[0];
Q[1]=line[1];
resn=0;
for(int i=2;i<tot;i++)
{
if(fabs((Q[tail].e-Q[tail].s)^(Q[tail-1].e-Q[tail-1].s)) < eps ||
fabs((Q[head].e-Q[head].s)^(Q[head+1].e-Q[head+1].s)) < eps )
return;
while(head<tail && (((Q[tail]&Q[tail-1]) - line[i].s) ^ (line[i].e-line[i].s)) > eps)
tail--;
while(head<tail && (((Q[head]&Q[head+1]) - line[i].s) ^ (line[i].e-line[i].s)) > eps)
head++;
Q[++tail]=line[i];
}
while(head<tail && (((Q[tail]&Q[tail-1]) - Q[head].s) ^ (Q[head].e-Q[head].s)) > eps)
tail--;
while(head<tail && (((Q[head]&Q[head+1]) - Q[tail].s) ^ (Q[tail].e-Q[tail].s)) > eps)
tail--;
while(tail<=head+1)return;
for(int i=head;i<tail;i++) // 保存内核点
res[resn++]=Q[i]&Q[i+1];
res[resn++]=Q[head]&Q[tail];
}
double CalcArea(Point p[],int n)
{
double ans=0;
for(int i=0;i<n;i++)
{
ans+=(p[i]^p[(i+1)%n])/2;
}
return ans;
}
int main()
{
int T;
Point p[1510];
Line line[1510];
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%lf%lf",&p[i].x,&p[i].y);
if(CalcArea(p,n)<0) // 判断给的点的顺序,使其为逆序
reverse(p,p+n);
for(int i=0;i<n;i++)
line[i]=Line(p[i],p[(i+1)%n]);
int resn=0;
HPI(line,n,p,resn);
// cout<<resn<<endl;
printf("%.2f\n",CalcArea(p,resn));
}
return 0;
}