1. 程式人生 > >hdu2892 圓與多邊形交模板

hdu2892 圓與多邊形交模板

轉自:http://www.cnblogs.com/mypsq/p/4366893.html

HDU - 2892 area
Time Limit: 1000MS   Memory Limit: 32768KB   64bit IO Format: %I64d & %I64u

 Status

Description

小白最近被空軍特招為飛行員,參與一項實戰演習。演習的內容是轟炸某個島嶼。。。 
作為一名優秀的飛行員,任務是必須要完成的,當然,憑藉小白出色的操作,順利地將炸彈投到了島上某個位置,可是長官更關心的是,小白投擲的炸彈到底摧毀了島上多大的區域? 
島是一個不規則的多邊形,而炸彈的爆炸半徑為R。 
小白只知道自己在(x,y,h)的空間座標處以(x1,y1,0)的速度水平飛行時投下的炸彈,請你計算出小白所摧毀的島嶼的面積有多大. 重力加速度G = 10. 

Input

首先輸入三個數代表小白投彈的座標(x,y,h); 
然後輸入兩個數代表飛機當前的速度(x1, y1); 
接著輸入炸彈的爆炸半徑R; 
再輸入一個數n,代表島嶼由n個點組成; 
最後輸入n行,每行輸入一個(x',y')座標,代表島嶼的頂點(按順勢針或者逆時針給出)。(3<= n < 100000) 

Output

輸出一個兩位小數,表示實際轟炸到的島嶼的面積。

模板:

#include"cstdio"
#include"cstring"
#include"cstdlib"
#include"cmath"
#include"string"
#include"map"
#include"cstring"
#include"algorithm"
#include"iostream"
#include"set"
#include"queue"
#include"stack"
#define inf 1000000000000
#define M 100009
#define LL long long
#define eps 1e-12
#define mod 1000000007
#define PI acos(-1.0)
using namespace std;
struct node
{
    double x,y;
    node(){}
    node(double xx,double yy)
    {
        x=xx;
        y=yy;
    }
    node operator -(node s)
    {
        return node(x-s.x,y-s.y);
    }
    node operator +(node s)
    {
        return node(x+s.x,y+s.y);
    }
    double operator *(node s)
    {
        return x*s.x+y*s.y;
    }
    double operator ^(node s)
    {
        return x*s.y-y*s.x;
    }
}p[M];
double max(double a,double b)
{
    return a>b?a:b;
}
double min(double a,double b)
{
    return a<b?a:b;
}
double len(node a)
{
    return sqrt(a*a);
}
double dis(node a,node b)//兩點之間的距離
{
    return len(b-a);
}
double cross(node a,node b,node c)//叉乘
{
    return (b-a)^(c-a);
}
double dot(node a,node b,node c)//點成
{
    return (b-a)*(c-a);
}
int judge(node a,node b,node c)//判斷c是否在ab線段上(前提是c在直線ab上)
{
    if(c.x>=min(a.x,b.x)
       &&c.x<=max(a.x,b.x)
       &&c.y>=min(a.y,b.y)
       &&c.y<=max(a.y,b.y))
        return 1;
    return 0;
}
double area(node b,node c,double r)
{
    node a(0.0,0.0);
    if(dis(b,c)<eps)
        return 0.0;
    double h=fabs(cross(a,b,c))/dis(b,c);
    if(dis(a,b)>r-eps&&dis(a,c)>r-eps)//兩個端點都在圓的外面則分為兩種情況
    {
        double angle=acos(dot(a,b,c)/dis(a,b)/dis(a,c));
        if(h>r-eps)
        {
            return 0.5*r*r*angle;
        }
        else if(dot(b,a,c)>0&&dot(c,a,b)>0)
        {
            double angle1=2*acos(h/r);
            return 0.5*r*r*fabs(angle-angle1)+0.5*r*r*sin(angle1);
        }
        else
        {
            return 0.5*r*r*angle;
        }
    }
    else if(dis(a,b)<r+eps&&dis(a,c)<r+eps)//兩個端點都在圓內的情況
    {
        return 0.5*fabs(cross(a,b,c));
    }
    else//一個端點在圓上一個端點在圓內的情況
    {
        if(dis(a,b)>dis(a,c))//預設b在圓內
        {
            swap(b,c);
        }
        if(fabs(dis(a,b))<eps)//ab距離為0直接返回0
        {
            return 0.0;
        }
        if(dot(b,a,c)<eps)
        {
            double angle1=acos(h/dis(a,b));
            double angle2=acos(h/r)-angle1;
            double angle3=acos(h/dis(a,c))-acos(h/r);
            return 0.5*dis(a,b)*r*sin(angle2)+0.5*r*r*angle3;

        }
        else
        {
            double angle1=acos(h/dis(a,b));
            double angle2=acos(h/r);
            double angle3=acos(h/dis(a,c))-angle2;
            return 0.5*r*dis(a,b)*sin(angle1+angle2)+0.5*r*r*angle3;
        }
    }
}
int main()
{
    double x,y,h,x1,y1,R;
    while(scanf("%lf%lf%lf",&x,&y,&h)!=-1)
    {
        scanf("%lf%lf%lf",&x1,&y1,&R);
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            scanf("%lf%lf",&p[i].x,&p[i].y);
        }
        p[n]=p[0];
        double V=sqrt(2*10*h);
        double t0=V/10;
        double x0=x+x1*t0;
        double y0=y+y1*t0;
        node O(x0,y0);
        for(int i=0;i<=n;i++)
            p[i]=p[i]-O;
        O=node(0,0);
        double sum=0;
        for(int i=0;i<n;i++)
        {
            int j=i+1;
            double s=area(p[i],p[j],R);
            if(cross(O,p[i],p[j])>0)
                sum+=s;
            else
                sum-=s;
        }
        printf("%.2lf\n",fabs(sum));
    }
    return 0;
}