【题解】[CQOI2006] 洛谷P4196 凸多边形 /【模板】半平面交
前置知识:
半平面交相关知识
建议先看看我写的半平面交笔记,这样承上启下
题面:
洛谷P4196
解析:
看上去给了很多个多边形,实际上还是一堆边,全部放到数组里排个序,直接半平面交。
相比于笔记那道题,这次的多边形是封闭的,需要踢队头,也要考虑多边形封口。
其他没啥了,直接看代码:
#include<bits/stdc++.h>
using namespace std;const int N = 1010;
const double eps = 1e-12;struct point {double x, y;
} P[N], b[N];
struct line {point s, e;
} a[N], q[N];point operator+(point a, point b) {return { a.x + b.x, a.y + b.y };
}point operator-(point a, point b) {return { a.x - b.x, a.y - b.y };
}point operator*(point a, double t) {return { a.x * t, a.y * t };
}double operator*(point a, point b) {return a.x * b.y - a.y * b.x;
}double angle(line a) {return atan2(a.e.y - a.s.y, a.e.x - a.s.x);
}bool cmp(line a, line b) {double A = angle(a), B = angle(b);if (fabs(A - B) > eps) {return A < B;} else {return ( a.e - a.s ) * (b.e - a.s) < 0;}
}point cross(line a, line b) {point u = a.s - b.s;point v = a.e - a.s;point w = b.e - b.s;double t = (u * w) / (w * v);return a.s + v * t;
}bool right(line a, line b, line c) {point p = cross(b, c);return ( a.e - a.s ) * ( p - a.s ) <= 0;
}int n;void half_plane(){sort( a + 1, a + n + 1, cmp);int head = 1, tail = 1;q[1] = a[1];for (int i = 2; i <= n; i++) {if (angle(a[i]) - angle(a[i-1]) < eps) continue;while ( (head < tail) && right(a[i], q[tail - 1], q[tail]) ) {tail--;}while ( (head < tail) && right(a[i], q[head], q[head + 1]) ) {head++;}tail++;q[tail] = a[i];}while ( (head < tail) && right(q[tail - 1], q[tail], q[head]) ) {tail--;}tail++;q[tail] = q[head];int len = 0;for (int i = head; i < tail; i++) {len++;P[len] = cross(q[i], q[i + 1]);}double ans = 0;for (int i = 2; i < len; i++) {ans = ans + ( P[i] - P[1] ) * ( P[i + 1] - P[1] );}cout << fixed << setprecision(3) << ans / 2 << endl;
}int main() {ios::sync_with_stdio(false);cin.tie(0);int num; n = 0;cin >> num;for (int i = 1; i <= num; i++){int m;cin >> m;for (int j = 1; j <= m; j++) {cin >> b[j].x >> b[j].y;}for (int j = 1; j <= m; j++) {n++;a[n] = {b[j], b[(j % m) + 1]};}}half_plane();return 0;
}