Description
Input
Output
Sample Input
12 3 3 4 6 4 11 4 8 10 6 5 7 6 6 6 3 7 9 10 4 10 9 1 7 5 20 20 20 40 40 20 40 40 30 30 3 10 10 21 10 21 13 -1 5 5 20 12
Sample Output
70.50
题意:给你N个王国,求下凸包,再求面积。给你一些炮弹,问炮弹炸掉的面积。(一个炮弹炸的话,整个王国都被炸了)。
思路:这题一看就是面积嘛,只不过需要判定点在哪个凸包里面才得取,而且每个凸包的面积只能取一次,因为炸掉的面积重新炸第二次就木有了。
不过与前几题练习不同的地方就是这里有很多个凸包,然后我一想,就把vector改成了二维的了……然后逗了……输入老是运行崩溃,妹妹滴!!!检查好久也看不出哪个错啊,而且已经把二维的长度给resize了还出错,改了一个多小时实在不行了,就看了眼奎神的代码……晕……就知道自己思想不够开放了。
干嘛跟vector过不去呢,把结构体开个数组不就解决了嘛!唉……自己还是太弱了,把结构体数组给忘了,哈哈……
#include <iostream> #include <cstdio> #include <fstream> #include <algorithm> #include <cmath> #include <deque> #include <vector> #include <list> #include <queue> #include <string> #include <cstring> #include <map> #include <stack> #include <set> #define PI acos(-1.0) #define eps 1e-8 #define mem(a,b) memset(a,b,sizeof(a)) #define sca(a) scanf("%d",&a) #define pri(a) printf("%d\n",a) #define f(i,a,n) for(i=a;i<n;i++) #define F(i,a,n) for(i=a;i<=n;i++) #define MM 100005 #define MN 505 #define INF 10000007 using namespace std; typedef long long ll; int sgn(const double &x){ return x < -eps? -1 : (x > eps);} inline double sqr(const double &x){ return x * x;} inline int gcd(int a, int b){ return !b? a: gcd(b, a % b);} struct Point { double x, y; Point(const double &x = 0, const double &y = 0):x(x), y(y){} Point operator -(const Point &a)const{ return Point(x - a.x, y - a.y);} Point operator +(const Point &a)const{ return Point(x + a.x, y + a.y);} Point operator *(const double &a)const{ return Point(x * a, y * a);} Point operator /(const double &a)const{ return Point(x / a, y / a);} bool operator < (const Point &a)const{ return sgn(x - a.x) < 0 || (sgn(x - a.x) == 0 && sgn(y - a.y) < 0);} bool operator == (const Point &a)const{ return sgn(sgn(x - a.x) == 0 && sgn(y - a.y) == 0);} friend double det(const Point &a, const Point &b){ return a.x * b.y - a.y * b.x;} friend double dot(const Point &a, const Point &b){ return a.x * b.x + a.y * b.y;} friend double dist(const Point &a, const Point &b){ return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y));} void in(){ scanf("%lf %lf", &x, &y); } void out()const{ printf("%lf %lf\n", x, y); } }; struct Poly //多边形类 { //vector<Point>a; vector<Point>p; //顺时针凸包 vector<Point>tb;// 逆时针凸包 void in(const int &r) { p.resize(r); //不早凸包的时候可以把p改为a for(int i = 0; i < r; i++) p[i].in(); } //计算多边形的面积 double getArea() { int n = tb.size(); //平常的多边形就把tb换成a double ans=0; for(int i = 0; i < n; i++) ans += det(tb[i], tb[(i + 1)%n]); return ans / 2; } //判断点集是否为凸包(返回m-1==n),或者用凸包点算出凸包顶点tb(本题即是) void isCanHull() { sort(p.begin(), p.end()); p.erase(unique(p.begin(), p.end()), p.end()); int n = p.size(); tb.resize(n * 2 + 5); int m = 0; for(int i = 0; i < n; i++) { while(m > 1 && sgn(det(tb[m - 1] - tb[m - 2], p[i] - tb[m - 2])) <= 0)m--; tb[m++] = p[i]; } int k = m; for(int i = n - 2; i >= 0; i--) { while(m > k && sgn(det(tb[m - 1] - tb[m -2], p[i] - tb[m - 2])) <= 0)m--; tb[m++] = p[i]; } tb.resize(m); if(m > 1)tb.resize(m - 1); //for(int i = 0; i < m - 1; i++) tb[i].out(); } //判断点t(圆心)是否在凸包内部,这个是O(logn)的算法 int isContainOlogn(const Point &t) { int n = tb.size(); if(n < 3) return 0; Point g = (tb[0] + tb[n / 3] + tb[n * 2 / 3] )/ 3.0; int l = 0, r = n; while(l + 1 < r) { int mid = (l + r) >> 1; int k = sgn(det(tb[l] - g, tb[mid] - g) ); int dl = sgn(det(tb[l] - g, t - g) ); int dr = sgn(det(tb[mid] - g, t - g) ); if(k > 0) { if(dl >= 0 && dr < 0) r = mid; else l = mid; } else { if(dl < 0 && dr >= 0) l = mid; else r = mid; } } r %= n; int res = sgn(det(tb[l] - t, tb[r] - t)); if(res >= 0) return 1; return 0; } }poly[MM]; double sum=0,a,b; int n,i,k=0,vis[MM]; int main() { while(sca(n)&&n!=-1) { poly[k].in(n); poly[k++].isCanHull(); } while(~scanf("%lf%lf",&a,&b)) { Point bb(a,b); for(i=0;i<k;i++) if(!vis[i]&&poly[i].isContainOlogn(bb)) sum+=poly[i].getArea(),vis[i]=1; } printf("%.2f\n",sum); return 0; }