题目链接
2803. 凸多边形
逆时针给出 \(n\) 个凸多边形的顶点坐标,求它们交的面积。
例如 \(n=2\) 时,两个凸多边形如下图:
则相交部分的面积为 \(5.233\)。
输入格式
第一行有一个整数 \(n\),表示凸多边形的个数,以下依次描述各个多边形。
第 \(i\) 个多边形的第一行包含一个整数 \(m_i\),表示多边形的边数,以下 \(m_i\) 行每行两个整数,逆时针给出各个顶点的坐标。
输出格式
仅包含一个实数,表示相交部分的面积,保留三位小数。
数据范围
\(2 \le n \le 10\),
\(3 \le m_i \le 50\),
每维坐标为 \([-1000,1000]\) 内的整数。
输入样例:
2
6
-2 0
-1 -2
1 -2
2 0
1 2
-1 2
4
0 -3
1 -1
2 2
-1 0
输出样例:
5.233
解题思路
半平面交
先将所有直线极角排序,用栈存储最后保存的直线,对于当前直线,如果其在前两个直线交点的左边,则显然不行,需要出栈,最后要闭合需要判断首尾两条边
- 时间复杂度:\(O(nlogn)\)
代码
// Problem: 凸多边形
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/2805/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=505;
const double eps=1e-8;
typedef pair<double,double> PDD;
int n,m,cnt,q[N];
PDD a[N],ans[N];
struct Line
{
PDD st,en;
}line[N];
PDD operator-(PDD a,PDD b)
{
return {a.fi-b.fi,a.se-b.se};
}
int sign(double x)
{
if(fabs(x)<eps)return 0;
if(x<0)return -1;
return 1;
}
int dcmp(double x,double y)
{
if(fabs(x-y)<eps)return 0;
if(x>y)return 1;
return -1;
}
double cross(PDD a,PDD b)
{
return a.fi*b.se-b.fi*a.se;
}
double area(PDD a,PDD b,PDD c)
{
return cross(b-a,c-a);
}
double get_angle(Line a)
{
return atan2(a.en.se-a.st.se,a.en.fi-a.st.fi);
}
bool cmp(const Line &a,const Line &b)
{
double A=get_angle(a),B=get_angle(b);
if(!dcmp(A,B))return area(a.st,a.en,b.en)<0;
return A<B;
}
PDD get_line_intersection(PDD p,PDD v,PDD q,PDD w)
{
PDD u=p-q;
double t=cross(w,u)/cross(v,w);
return {p.fi+t*v.fi,p.se+t*v.se};
}
PDD get_line_intersection(Line a,Line b)
{
return get_line_intersection(a.st,a.en-a.st,b.st,b.en-b.st);
}
bool on_right(Line a,Line b,Line c)
{
PDD o=get_line_intersection(b,c);
return sign(area(a.st,a.en,o))<=0;
}
double half_plane_intersection()
{
double res=0;
sort(line+1,line+cnt+1,cmp);
int hh=0,tt=-1;
for(int i=1;i<=cnt;i++)
{
if(i>1&&!dcmp(get_angle(line[i]),get_angle(line[i-1])))continue;
while(hh+1<=tt&&on_right(line[i],line[q[tt-1]],line[q[tt]]))tt--;
while(hh+1<=tt&&on_right(line[i],line[q[hh]],line[q[hh+1]]))hh++;
q[++tt]=i;
}
while(hh+1<=tt&&on_right(line[q[hh]],line[q[tt-1]],line[q[tt]]))tt--;
while(hh+1<=tt&&on_right(line[q[tt]],line[q[hh]],line[hh+1]))hh++;
q[++tt]=q[hh];
int k=0;
for(int i=hh;i<tt;i++)ans[++k]=get_line_intersection(line[q[i]],line[q[i+1]]);
for(int i=2;i+1<=k;i++)res+=area(ans[1],ans[i],ans[i+1]);
return res/2;
}
int main()
{
for(scanf("%d",&n);n;n--)
{
scanf("%d",&m);
for(int i=0;i<m;i++)scanf("%lf%lf",&a[i].fi,&a[i].se);
for(int i=0;i<m;i++)line[++cnt]={a[i],a[(i+1)%m]};
}
printf("%.3lf",half_plane_intersection());
return 0;
}
标签:return,凸多边形,fi,2803,PDD,se,define
From: https://www.cnblogs.com/zyyun/p/16895795.html