UVA 109 || SCUD Busters(凸包面积计算

来源:互联网 发布:阿里大数据应用 编辑:程序博客网 时间:2024/05/16 14:40


 = = 模板水题。看数据就可以做了。



输出被炸弹轰炸之后,所有王国停电的总面积,保留小数点后两位。

题目中说到每个王国的边界是围城这些点的最小周长,所以可以推出,每个王国都是一个凸包圈住的点集;

第一步计算出凸包,在算出面积就好了。(已经停电的面积不可以重复累加。


#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;}


0 0