[CQOI2006]凸多邊形(半平面相交)
阿新 • • 發佈:2018-11-23
嘟嘟嘟
本來我要寫feng shui這道題的。然後網上都說什麼半平面相交,於是我還得現學這個東西,就來刷這道模板題了。
所謂的半平面相交和高中數學的分數規劃特別像。比如這道題,把每一條邊看成一條有向直線,則合法的範圍都是直線的右半部分,最後求交集。大概是每一次都取一半,所以就叫半平面相交吧。
\(O(n ^ 2)\)的做法很簡單,我也只會\(O(n ^ 2)\)的。列舉每一條邊,然後用這條邊去切當前算出來的圖形。
具體怎麼切?一句話就是把這條直線左邊的點全部扔掉。
放個虛擬碼就明白了:
for 每條邊ai ai+1 if (ai在AB右邊) 把ai加入答案 if (ai+1在AB左邊) 把交點加入答案 else if(ai+1在AB右邊) 把交點加入答案
至於判斷左右,用叉積求又向面積就行了。
#include<cstdio> #include<iostream> #include<cmath> #include<algorithm> #include<cstring> #include<cstdlib> #include<cctype> #include<vector> #include<stack> #include<queue> using namespace std; #define enter puts("") #define space putchar(' ') #define Mem(a, x) memset(a, x, sizeof(a)) #define rg register typedef long long ll; typedef double db; const int INF = 0x3f3f3f3f; const db eps = 1e-8; const int maxn = 5e5 + 5; inline ll read() { ll ans = 0; char ch = getchar(), last = ' '; while(!isdigit(ch)) {last = ch; ch = getchar();} while(isdigit(ch)) {ans = (ans << 1) + (ans << 3) + ch - '0'; ch = getchar();} if(last == '-') ans = -ans; return ans; } inline void write(ll x) { if(x < 0) x = -x, putchar('-'); if(x >= 10) write(x / 10); putchar(x % 10 + '0'); } int n, m, cnt = 0; struct Point { db x, y; Point operator - (const Point& oth)const { return (Point){x - oth.x, y - oth.y}; } db operator * (const Point& oth)const { return x * oth.y - oth.x * y; } Point operator * (const db& d)const { return (Point){x * d, y * d}; } }p[maxn], a[maxn]; int tot = 0; Point b[maxn]; db cross(Point A, Point B, Point C) { return (B - A) * (C - A); } void addCross(Point A, Point B, Point C, Point D) { db s1 = (C - A) * (D - A), s2 = (D - B) * (C - B); b[++tot] = A - (A - B) * (s1 / (s1 + s2)); } void cut(Point A, Point B) { tot = 0; a[cnt + 1] = a[1]; for(int i = 1; i <= cnt; ++i) { if(cross(A, B, a[i]) >= 0) { b[++tot] = a[i]; if(cross(A, B, a[i + 1]) < 0) addCross(A, B, a[i], a[i + 1]); } else if(cross(A, B, a[i + 1]) > 0) addCross(A, B, a[i], a[i + 1]); } for(int i = 1; i <= tot; ++i) a[i] = b[i]; cnt = tot; } int main() { n = read(); m = read(); for(int i = 1; i <= m; ++i) a[i].x = read(), a[i].y = read(); cnt = m; n--; while(n--) { m = read(); for(int i = 1; i <= m; ++i) p[i].x = read(), p[i].y = read(); p[m + 1] = p[1]; for(int i = 1; i <= m; ++i) cut(p[i], p[i + 1]); } a[cnt + 1] = a[1]; db ans = 0; for(int i = 1; i <= cnt; ++i) ans += a[i] * a[i + 1]; printf("%.3lf\n", ans / 2); return 0; }