【模板】半平面交

参考题目:CQOI2006凸多边形


解析:

联赛结束后统一更模板题题解


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

inline int getint(){
	re int num;
	re char c;
	re bool f=0;
	while(!isdigit(c=gc()))if(c=='-')f=1;num=c^48;
	while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
	return f?-num:num;
}

cs double eps=1e-8;
cs int N=505;
int n,tot;
struct Point{
	double x,y;
	Point(cs double &_x=0,cs double &_y=0):x(_x),y(_y){}
	friend Point operator+(cs Point &a,cs Point &b){return Point(a.x+b.x,a.y+b.y);}
	friend Point operator-(cs Point &a,cs Point &b){return Point(a.x-b.x,a.y-b.y);}
	friend double operator*(cs Point &a,cs Point &b){return a.x*b.y-b.x*a.y;}
	friend double dot(cs Point &a,cs Point &b){return a.x*b.x+b.y*a.y;}
	friend Point operator*(cs Point &a,cs double &b){return Point(a.x*b,a.y*b);}
}b[N];

inline int sign(cs double &x){
	return fabs(x)<=eps?0:(x>0?1:-1);
}

struct Line{
	Point s,e;
	double rad;
	friend bool operator<(cs Line &a,cs Line &b){
		return sign(a.rad-b.rad)==0?sign((a.e-a.s)*(b.e-a.s))>0:sign(a.rad-b.rad)<0;
	}
}a[N],q[N];

inline Point InterSection(cs Line &a,cs Line &b){
	double s1=(a.s-a.e)*(b.e-a.e),s2=(b.s-a.e)*(a.s-a.e);
	double k=s2/(s1+s2);
	return b.s+(b.e-b.s)*k;
}

inline bool judge(cs Line &a,cs Line &b,cs Line &c){
	return sign((c.e-c.s)*(InterSection(a,b)-c.s))<0;
}

int head,tail;
void half_plane_inter(){
	n=0;
	sort(a+1,a+tot+1);
	for(int re i=1;i<=tot;++i){
		if(sign(a[i].rad-a[i-1].rad))++n;
		a[n]=a[i];
	}
	head=1,tail=2;
	q[1]=a[1],q[2]=a[2];
	for(int re i=3;i<=n;++i){
		while(head<tail&&judge(q[tail-1],q[tail],a[i]))--tail;
		while(head<tail&&judge(q[head+1],q[head],a[i]))++head;
		q[++tail]=a[i];
	}
	while(head<tail&&judge(q[tail-1],q[tail],q[head]))--tail;
	while(head<tail&&judge(q[head+1],q[head],q[tail]))++head;
	n=0;q[tail+1]=q[head];
	for(int re i=head;i<=tail;++i)b[++n]=InterSection(q[i],q[i+1]);
}

inline double area(){
	double ans=0;
	for(int re i=1;i<=n;++i)ans+=b[i]*b[i%n+1];
	return fabs(ans)/2;
}

signed main(){
	n=getint();
	for(int re i=1;i<=n;++i){
		int k=getint();
		for(int re j=1;j<=k;++j)b[j].x=getint(),b[j].y=getint();
		for(int re j=1;j<=k;++j)a[++tot].s=b[j],a[tot].e=b[j%k+1];
	}
	for(int re i=1;i<=tot;++i)a[i].rad=atan2(a[i].e.y-a[i].s.y,a[i].e.x-a[i].s.x);
	half_plane_inter();
	printf("%.3f",area());
	return 0;
} 

转载于:https://www.cnblogs.com/zxyoi/p/10047206.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值