模板半平面交
Posted nublity
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了模板半平面交相关的知识,希望对你有一定的参考价值。
P4196 [CQOI2006]凸多边形
题目描述
逆时针给出n个凸多边形的顶点坐标,求它们交的面积。例如n=2时,两个凸多边形如下图:
则相交部分的面积为5.233。
输入格式
第一行有一个整数n,表示凸多边形的个数,以下依次描述各个多边形。第i个多边形的第一行包含一个整数mi,表示多边形的边数,以下mi行每行两个整数,逆时针给出各个顶点的坐标。
输出格式
输出文件仅包含一个实数,表示相交部分的面积,保留三位小数。
输入输出样例
输入 #1
2
6
-2 0
-1 -2
1 -2
2 0
1 2
-1 2
4
0 -3
1 -1
2 2
-1 0
输出 #1
5.233
说明/提示
100%的数据满足:2<=n<=10,3<=mi<=50,每维坐标为[-1000,1000]内的整数
题解都在代码里
#include<bits/stdc++.h>//半平面交 #define ll long long using namespace std; const int N = 1100; int n, cnt, tot; double ans; struct P double x, y; p[N], a[N]; struct L P a, b; double val;//atan2 l[N], q[N]; P operator-(P a, P b) P t; t.x = a.x - b.x; t.y = a.y - b.y; return t; double operator*(P a, P b) // 叉积 return a.x * b.y - a.y * b.x; bool operator<(L a, L b) //极角排序 if (a.val != b.val)return a.val < b.val;// 角度 return (a.b - a.a) * (b.b - a.a) > 0;//通过叉积的正向性来判断相同角度的向量,极角小的排在前 P inter(L a, L b) //求两直线的交点 double k1, k2, t; k1 = (b.b - a.a) * (a.b - a.a); k2 = (a.b - a.a) * (b.a - a.a); t = k1 / (k1 + k2); P ans; ans.x = b.b.x + (b.a.x - b.b.x) * t; ans.y = b.b.y + (b.a.y - b.b.y) * t; return ans; bool check(L a, L b, L t) //判断该直线是否对队首或队尾元素有影响 P p = inter(a, b);//前两条直线的交点 return (t.b - t.a) * (p - t.a) < 0;//如果该直线的极角比交点的大,则弹出该元素 void hpi() //半平面交 sort(l + 1, l + cnt + 1);//极角排序 int L = 1, R = 0; tot = 0; for (int i = 1; i <= cnt; i++) if (l[i].val != l[i - 1].val)tot++; l[tot] = l[i];//斜率相同的优先取极角大的,因为是逆时针 cnt = tot; tot = 0; q[++R] = l[1];//单调队列 q[++R] = l[2]; for (int i = 3; i <= cnt; i++) while (L < R && check(q[R - 1], q[R], l[i]))R--;//先判断队尾 while (L < R && check(q[L + 1], q[L], l[i]))L++;//后判断队首 q[++R] = l[i];// 元素入队 while (L < R && check(q[R - 1], q[R], q[L]))R--;//最后用队首的向量排除一下队尾多余的向量 while (L < R && check(q[L + 1], q[L], q[R]))L++;//应该没必要 q[R + 1] = q[L]; for (int i = L; i <= R; i++) a[++tot] = inter(q[i], q[i + 1]); void getans() // 求凸包面积 if (tot < 3)return; a[++tot] = a[1]; for (int i = 1; i <= tot; i++)//所有点和后面的点叉积和/2 ans += a[i] * a[i + 1]; ans = fabs(ans) / 2; int main() ios::sync_with_stdio(false); cin.tie(0); cin >> n; for (int i = 1; i <= n; i++) int k; cin >> k; for (int j = 1; j <= k; j++) cin >> p[j].x >> p[j].y; p[k + 1] = p[1]; for (int j = 1; j <= k; j++) l[++cnt].a = p[j], l[cnt].b = p[j + 1];//存成直线 for (int i = 1; i <= cnt; i++) l[i].val = atan2(l[i].b.y - l[i].a.y, l[i].b.x - l[i].a.x); hpi(); getans(); cout << fixed << setprecision(3) << ans << endl; return 0;
以上是关于模板半平面交的主要内容,如果未能解决你的问题,请参考以下文章