POJ 2451 Uyuw's Concert(半平面交求面积)

POJ 2451 Uyuw's Concert(半平面交求面积)

http://poj.org/problem?id=2451

题意:

      给你一个矩形框(左下角[0,0],右上角[10000,10000]),然后给你n条从(x1,y1)到(x2,y2)的有向直线(测试得出直线方向). 问你这些有向直线的左边的交集面积(处于矩形框内的)有多大.

分析:

       很明显的半平面交问题了,首先添加4条带方向直线:

点: (0, 0) , 方向向量: (10000, 0)

点: (10000, 0) , 方向向量: (0, 10000)

点: (10000, 10000) , 方向向量: (-10000, 0)

点: (0, 10000) , 方向向量: (0, -10000)

       然后对于每个输入直线(x1,y1)和(x2,y2). 添加对应直线:

点: (x1,y1), 方向向量: (x2-x1,y2-y1)

       最终求出半平面交的凸多边形即可(本题要么不存在半平面交的部分,要么一定是凸多边形. 不会出现无界区域).

然后输出该凸多边形的面积.

AC代码: 要用C++提交, G++提交有精度问题

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;

//精度控制
const double eps=1e-10;
int dcmp(double x)
{
    if(fabs(x)<eps) return 0;
    return x<0?-1:1;
}

//点
struct Point
{
    double x,y;
    Point(){}
    Point(double x,double y):x(x),y(y){}
};

//向量
typedef Point Vector;

//点-点==向量
Vector operator-(Point A,Point B)
{
    return Vector(A.x-B.x,A.y-B.y);
}

//向量+向量==向量
Vector operator+(Vector A,Vector B)
{
    return Vector(A.x+B.x,A.y+B.y);
}

//向量*实数==向量
Vector operator*(Vector A,double p)
{
    return Vector(A.x*p, A.y*p);
}

//叉积
double Cross(Vector A,Vector B)
{
    return A.x*B.y-A.y*B.x;
}

//多边形面积
double PolygonArea(Point *p,int n)
{
    double area=0;
    for(int i=1;i<n-1;i++)
        area += Cross(p[i]-p[0],p[i+1]-p[0]);
    return fabs(area)/2;
}

//带方向直线
struct Line
{
    Point p;
    Vector v;
    double ang;
    Line(){}
    Line(Point p,Vector v):p(p),v(v)
    {
        ang=atan2(v.y,v.x);
    }
    bool operator<(const Line& rhs)const
    {
        return ang<rhs.ang;
    }
};

//判断点P是否在直线L左边
bool OnLeft(Line L,Point p)
{
    return Cross(L.v,p-L.p)>0;
}

//求直线交点
Point GetIntersection(Line a,Line b)
{
    Vector u=a.p-b.p;
    double t=Cross(b.v,u)/Cross(a.v,b.v);
    return a.p+a.v*t;
}

//求半平面交
int HalfplaneIntersection(Line *L,int n,Point *poly)
{
    sort(L,L+n);

    int first=0,last=0;
    Point *p=new Point[n];
    Line *q=new Line[n];
    q[0]=L[0];

    for(int i=1;i<n;i++)
    {
        while(first<last && !OnLeft(L[i],p[last-1])) last--;
        while(first<last && !OnLeft(L[i],p[first])) first++;
        q[++last]=L[i];

        if(fabs(Cross(q[last].v,q[last-1].v))<eps)
        {
            last--;
            if(OnLeft(q[last],L[i].p)) q[last]=L[i];
        }

        if(first<last)
            p[last-1]=GetIntersection(q[last],q[last-1]);
    }

    while(first<last && !OnLeft(q[first], p[last-1])) last--;

    if(last-first<=1) return 0;

    p[last]=GetIntersection(q[last],q[first]);

    int m=0;
    for(int i=first;i<=last;i++) poly[m++]=p[i];
    return m;
}
/***以上为刘汝佳模板***/

const int maxn=20000+10;
Point p[maxn],poly[maxn];
Line L[maxn];

int main()
{
    int n;
    while(scanf("%d",&n)==1)
    {
        n+=4;
        L[0]=Line(Point(0,0) ,Vector(10000,0));
        L[1]=Line(Point(10000,0) ,Vector(0,10000));
        L[2]=Line(Point(10000,10000) ,Vector(-10000,0));
        L[3]=Line(Point(0,10000) ,Vector(0,-10000));

        for(int i=4;i<n;i++)
        {
            Point p1,p2;
            scanf("%lf%lf%lf%lf",&p1.x,&p1.y,&p2.x,&p2.y);
            L[i]=Line(p1,p2-p1);
        }

        int m=HalfplaneIntersection(L,n,poly);

        double ans=0;
        if(m>0) ans=PolygonArea(poly,m);

        printf("%.1lf\n",ans);
    }
    return 0;
}

你可能感兴趣的:(Algorithm,算法,ACM,计算几何)