UVa 109 - SCUD Busters(凸包)

本文介绍了一种计算导弹袭击导致国家停电总面积的方法。通过求取国家边界构成的多边形凸包,并利用几何算法判断导弹落点是否在国境内来计算受影响的面积。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:输入n个国家,每个国家一些点,用围墙(多边形)围起来,围墙内的范围都属于这个国家,现在要发射一些导弹,如果导弹落到国家内,那对应的国家就会停电,现在问停电的总面积。

分析:1,求凸包,Graham扫描先把围墙上的点求出来,凸包完成。

2,求国家的面积,把多边形分成多个三角形,叉积a*b*sin<a,b>就是三角形面积的两倍,然后相加求得多边形面积。

3,判断点是否在多边形内,用射线进行判断,从该点引出射线,判断和多边形边相交的情况,注意射线和多边形交于多边形的顶点情况。





#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define N 111
#define EPS 1e-10
struct point
{
    double x,y;
    point(double x,double y):x(x),y(y){}
    point(){}
    bool operator< (const point &s)const
    {
        return (x-s.x<-EPS)||(abs(x-s.x)<EPS&&y<s.y);
    }
    double det(point a)
    {
        return x*a.y-y*a.x;
    }
    double dot(point a)
    {
        return x*a.x+y*a.y;
    }
    point operator-(point a)
    {
        return point(x-a.x,y-a.y);
    }
    point operator +(point a)
    {
        return point(x+a.x,y+a.y);
    }
    point operator *(double s)
    {
        return point(x*s,y*s);
    }

};
point p[N],res[N][N];
double s[N];
int kingdom[N],destory[N]={0};
point dir[4] = {point(501,-501),point(-501,501),point(501,501),point(-501,-501)};
bool ispointin(point p,int n);
point intersection(point p1,point p2,point q1,point q2);
bool on_seg(point p1,point p2,point p3);
double area(int n);
int main()
{
    int kingdom_num=0,n=0;
    while(~scanf("%d",&kingdom[n])&&kingdom[n]!=-1)
    {
        for(int i=0;i<kingdom[n];i++)
        {
            scanf("%lf%lf",&p[i].x,&p[i].y);
        }
        sort(p,p+kingdom[n]);
        int k=0;
        for(int i=0;i<kingdom[n];i++)//求下凸点
        {
            while(k>1&&(res[n][k-1]-res[n][k-2]).det(p[i]-res[n][k-2])<EPS)
            k--;
            res[n][k++]=p[i];
        }
          int t=k;
         for(int i=kingdom[n]-2;i>=0;i--)//求上凸点
          {
            while(k>t&&(res[n][k-1]-res[n][k-2]).det(p[i]-res[n][k-2])<EPS)
            k--;
            res[n][k++]=p[i];
          }
          kingdom[n]=k;
          s[n]=area(n);
          kingdom_num++;
          n++;
    }
    int x,y;
    double ans=0;
    while(~scanf("%d%d",&x,&y))
    {
        for(int i=0;i<kingdom_num;i++)
         {
             if(ispointin(point(x,y),i))
              {
                 ans+=s[i];
              }
         }
    }
    printf("%.2f\n",ans);
    return 0;
}
//求凸多边形面积
double area(int n)
{
    double sum=0;
    res[n][kingdom[n]]=res[n][0];
    for(int i=0;i<kingdom[n];i++)
    {
      sum=sum+(res[n][i].det(res[n][i+1]));
    }
    return sum/2;
}
//判断点是否在线段上
bool on_seg(point p1,point p2,point p3)
{
    return abs((p1-p3).det(p2-p3))<EPS&&(p1-p3).dot(p2-p3)<EPS;
}
//求两直线交点
point intersection(point p1,point p2,point q1,point q2)
{
    return p1+(p2-p1)*((q2-q1).det(q1-p1)/(q2-q1).det(p2-p1));
}
//判断点是否在多边形内
bool ispointin(point p,int n)
{
    if(destory[n])
        return 0;
    for(int i=0;i<4;i++)
    {
        int k=0;
         res[n][kingdom[n]-1]=res[n][0];

        for(int j=0;j<kingdom[n]-1;j++){
                if(on_seg(res[n][j],res[n][j+1],p))
                    return 1;
            point intersect=intersection(p,dir[i],res[n][j],res[n][j+1]);
            if(on_seg(res[n][j],res[n][j+1],intersect)&&on_seg(p,dir[i],intersect))
                    k++;
            if(on_seg(p,dir[i],res[n][j]))
                k--;
        }
        if(k%2==0)
            return 0;
    }
    destory[n]=1;
    return 1;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值