POJ2451.Uyuw’s Concert(半平面交)
题意:求半平面交的核面积。
思路:板子题,需要注意的是当半平面交是一个无限平面时,要预先用4个较大线段限制住。
时间复杂度:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const double eps=1e-9;
#define il inline
struct P{
double x,y;
}p[20005];
struct L{
P p1,p2; double g;
}A[20005],q[20005];
double ANS;
int n,top,bot,tot;
il P operator-(P a,P b){
P t; t.x=a.x-b.x; t.y=a.y-b.y;
return t;
}
il double operator*(P a,P b){ //叉乘.
return a.x*b.y-b.x*a.y;
}
il bool operator<(L a,L b){
if(a.g==b.g) return (b.p2-a.p1)*(b.p1-a.p1)>0;//越靠右,排名越靠前,会被覆盖掉
return a.g<b.g;
}
il P inter(L a,L b){
double k1,k2;//k1 k2 是两条线段四点连线所形成的两个三角形面积
k1=(b.p1-a.p1)*(b.p2-a.p1),k2=(b.p2-a.p2)*(b.p1-a.p2);
P p;
p.x=((a.p1.x)*k2+(a.p2.x)*k1)/(k1+k2);
p.y=((a.p1.y)*k2+(a.p2.y)*k1)/(k1+k2);
return p;
}
il bool jud(L a,L b,L t){//判断a和b的交点是不是在t内 ,在外部返回true
P p=inter(a,b);
return (t.p1-p)*(t.p2-p)<0;
}
void hpi(){
sort(A+1,A+n+1);//极角排序
for(int i=1;i<=n;i++){//去重
if(A[i].g!=A[i-1].g) tot++;
A[tot]=A[i];
}
n=tot,q[0]=A[1],q[1]=A[2],top=1,bot=0;
for(int i=3;i<=n;i++){
while(bot<top&&jud(q[top],q[top-1],A[i])) top--;
while(bot<top&&jud(q[bot],q[bot+1],A[i])) bot++;
q[++top]=A[i];
}
while(bot<top&&jud(q[top],q[top-1],q[bot])) top--;
while(bot<top&&jud(q[bot],q[bot+1],q[top])) bot++;
q[top+1]=q[bot],tot=0;
for(int i=bot;i<=top;i++)
p[++tot]=inter(q[i],q[i+1]);
}
il void solve(){
if(tot<3) return;p[++tot]=p[1];
for(int i=1;i<=tot;i++) //叉乘求多边形面积.
ANS+=p[i]*p[i+1];
ANS=fabs(ANS)/2;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lf%lf%lf%lf",&A[i].p1.x,&A[i].p1.y,&A[i].p2.x,&A[i].p2.y);
A[++n].p1={0,0},A[n].p2={10000,0},A[++n].p1={0,10000},A[n].p2={0,0}; //加入限制边界的四条线段.
A[++n].p1={10000,10000},A[n].p2={0,10000},A[++n].p1={10000,0},A[n].p2={10000,10000};
for(int i=1;i<=n;i++)//计算每条线段的极角,即与x轴夹角,便于极角排序.
A[i].g=atan2((A[i].p2.y-A[i].p1.y),(A[i].p2.x-A[i].p1.x));
hpi();solve();
printf("%.1f",ANS);//G++要用%.f
return 0;
}