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


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



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

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

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


#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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值