2803. 凸多边形

题目链接

2803. 凸多边形

逆时针给出 n 个凸多边形的顶点坐标,求它们交的面积。

例如 n=2 时,两个凸多边形如下图:

image

则相交部分的面积为 5.233

输入格式

第一行有一个整数 n,表示凸多边形的个数,以下依次描述各个多边形。

i 个多边形的第一行包含一个整数 mi,表示多边形的边数,以下 mi 行每行两个整数,逆时针给出各个顶点的坐标。

输出格式

仅包含一个实数,表示相交部分的面积,保留三位小数。

数据范围

2n10,
3mi50,
每维坐标为 [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; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/16895795.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(147)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
历史上的今天:
2021-11-16 华东交通大学2019年ACM 双基 程序设计竞赛
2021-11-16 矩阵乘法
点击右上角即可分享
微信分享提示