= = 模板水题。看数据就可以做了。
输出被炸弹轰炸之后,所有王国停电的总面积,保留小数点后两位。
题目中说到每个王国的边界是围城这些点的最小周长,所以可以推出,每个王国都是一个凸包圈住的点集;
第一步计算出凸包,在算出面积就好了。(已经停电的面积不可以重复累加。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int MX = 105;
struct point
{
double x,y,d;
point( double a,double b):x(a),y(b){}
point(){}
};
typedef point vec;
vec operator - ( point a,point b)
{
return vec(a.x-b.x,a.y-b.y);
}
struct poly
{
point p[MX];
int ver;//顶点数
point power;//电站
int bomb;// 已经被炸毁 1
};
point p0;//第一点
point b;//炸弹坐标
poly kingdom[25];
const double eps = 1e-6;
bool dd(double x,double y) { return fabs( x - y ) < eps;} // x == y
//点积
double dot(vec a,vec b )
{
return a.x*b.x + a.y*b.y;
}
// X积 corss( a-p,b-p )
double cross(vec a ,vec b)
{
return a.x*b.y - a.y*b.x;
}
double area( point *p,int n)
{
double s = 0.0;
for( int i = 1; i < n;++i)
{
s += cross(p[i] - p[0],p[i+1] - p[0]);
}
return fabs(s)*0.5;
}
//x,y最小的点
bool idcmp(point a ,point b)
{
return ( a.x == b.x )? ( a.y < b.y ): ( a.x < b.x );
}
//以选定的第一点与剩下的点连线进行级角排序
bool anglecmp(point a,point b)
{
double cp = cross( a- p0,b-p0) ;
if( dd(cp,0.0) )
return a.d < b.d;//级角相等距离由近到远
return cp > 0;
}
//距离
double dist(point a,point b)
{
vec A = a-b;
return sqrt(A.x*A.x + A.y*A.y );
}
int graham(point *p, int n)//定点数n
{
if( n > 1 )
{
sort( p,p+n,idcmp);//坐标排序
p0 = p[0];
for( int i = 1;i < n;++i)
p[i].d = dist(p[0],p[i]);//距离
sort(p+1,p+n,anglecmp);//级角排序
}
int top = n;//栈顶
if( n > 2 )//graham 最少三个顶点
{
top = 1;
for( int i = 2;i <n ;++i)
{
while( top > 0
&&cross( p[top]-p[ top-1],p[i]-p[ top-1])<0)
--top;
//栈顶两点与第i点不构成向左拐关系 栈顶回溯至满足条件
p[++top] = p[i];
}
p[++top] = p[0];//封闭
}
return top ;
}
int dcmp(double x)// 返回 -1 0 1
{
if( fabs(x) < eps )
return 0;
else
return x < 0?-1:1;
}
bool onsegment(point p,point a,point b)//点p在线段ab上
{
return dcmp(cross( a-p,b-p)) == 0 && dcmp(dot(a-p,b-p))< 0;
}
int ispointinpoly(point a,int n,point *p) //点a
{
int wn =0;
p[n] = p[0];//p[n]=p[0]循环处理
for( int i = 0;i<n;++i)
{
if(onsegment(a,p[i],p[i+1]) )return -1;//onsegment
int k = dcmp( cross(p[i+1]-p[i],a-p[i] ) );
int d1 = dcmp(p[i].y - a.y);
int d2 = dcmp(p[i+1].y - a.y);
if( k >0 && d1<=0 && d2>0)wn++;//射线逆时针穿过 i到i+1这两点间的线段 wn加一
if( k <0 && d2<=0 && d1>0)wn--;//顺时针则减一
}
if( wn!= 0)return 1;//indise
return 0;//outside
}
int main()
{
int n,j=0;
while( cin>>n && n!=-1)
{
for( int i = 0;i <n;++i)
scanf("%lf %lf",&kingdom[j].p[i].x,&kingdom[j].p[i].y);
kingdom[j].power = kingdom[j].p[0];
kingdom[j].bomb = 0;
kingdom[j].ver = n;
j++;
}
double sum = 0.0;//炸毁的总面积
while( cin>>b.x>>b.y )
{
for(int i = 0;i<j;++i)
{
//计算凸包
kingdom[i].ver = graham( kingdom[i].p,kingdom[i].ver);
if( !kingdom[i].bomb//炸弹第一次落到领土内
&&ispointinpoly(b,kingdom[i].ver,kingdom[i].p) )
{
sum += area(kingdom[i].p,kingdom[i].ver);
kingdom[i].bomb = 1;
}
}
}
printf("%.2lf\n",sum);
return 0;
}