SGU 412 计算几何

给出一个凸多边形,和一些墙壁阻挡,求被阴影覆盖的凸多边形的长度。

对墙壁进行离散化,计算出角度(atan2)排序后进行区间合并。

然后分别计算出每个区间造成的阴影部分的长度,最后相加即可。

注意计算阴影部分于多边形的交点时,朴素的o(n)算法会导致TLE。可以用二分去优化。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
     
#define mp make_pair
     
const int MAXN = 100010;
const double PI = 3.14159265358979323846264338327950288;
typedef pair<double,double> pa;
typedef vector<pa>::iterator iter;
     
     
struct Point
{
    double x,y;
    Point(double x=0,double y=0):x(x),y(y){}
    void input()
    {
        scanf("%lf%lf",&x,&y);
    }
    double getarg()
    {
        double r=atan2(y,x);
        if (r<0) r+=2*PI;
        return r;
    }
    double operator * (Point b)
    {
        return x*b.y-b.x*y;
    }
    Point operator - (Point b)
    {
        return Point(x-b.x,y-b.y);
    }
};
     
double dis(Point a,Point b)
{
    Point c=a-b;
    return sqrt(c.x*c.x+c.y*c.y);
}
     
double area(Point a,Point b,Point c)
{
    double rul=(b-a)*(c-a);
    return fabs(rul);
}
     
struct Sag
{
    Point a,b;
    double length;
    double arga,argb;
    void init()
    {
        length=dis(a,b);
        arga=a.getarg();
        argb=b.getarg();
    }
};
     
vector <pa> v;
Point wallp[MAXN];
Sag wall[MAXN];
int N,M;
double ans;
     
struct node
{
    double beg;
    int no;
    node(double b,int n):beg(b),no(n){}
    bool operator < (node b) const
    {
        return beg<b.beg;
    }
};
     
vector <node> vv;
     
void build()
{
    for (int i=0;i<N;i++)
    {
        if (wall[i].arga <= wall[i].argb) vv.push_back(node(wall[i].arga,i)); else
        {
            vv.push_back(node(wall[i].arga,i));
            vv.push_back(node(0,i));
        }
    }
    sort(vv.begin(),vv.end());
}
     
int cros(double k)
{
    int rul=0;
    rul = (upper_bound(vv.begin(),vv.end(),node(k,0))-1)->no;
    return rul;
}
     
double cro(Point A,Point B,Point C,Point D)
{
    return area(A,C,D)*dis(A,B)/(area(A,C,D)+area(B,C,D));
}
     
double calc(int p,double k)
{
    Point C;
    C.x=max(wall[p].a.x,wall[p].b.x)+10;
    C.y=tan(k)*C.x;
    Point D;
    D.x=-C.x;
    D.y=-C.y;
    return cro(wall[p].a,wall[p].b,C,D);
}
     
void cover(double l,double r)
{
    double rul=0;
    int indel=cros(l);
    int inder=cros(r);
    if (indel==inder) rul=calc(indel,r)-calc(indel,l); else
    {
        rul+=(wall[indel].length-calc(indel,l));
        for (int i=(indel+1)%N;i!=inder;i=(i+1)%N) rul+=wall[i].length;
        rul+=calc(inder,r);
    }
    ans+=rul;
}
     
int main()
{
    freopen("in.txt","r",stdin);
    scanf("%d%d",&N,&M);
    for (int i=0;i<N;i++) wallp[i].input();
    for (int i=0;i<N;i++) wall[i].a=wallp[i];
    for (int i=0;i<N-1;i++) wall[i].b=wallp[i+1];
    wall[N-1].b=wallp[0];
    for (int i=0;i<N;i++) wall[i].init();
    for (int i=0;i<M;i++)
    {
        Point a,b;
        a.input();
        b.input();
        double ra=a.getarg();
        double rb=b.getarg();
     
        if (ra>rb) swap(ra,rb);
        if (rb-ra<PI) v.push_back(mp(ra,rb)); else
        {
            v.push_back(mp(0,ra));
            v.push_back(mp(rb,2*PI));
        }
    }
     
    build();
    sort(v.begin(),v.end());
     
    ans=0;
    double l,r;
    l=r=0;
    for (iter k=v.begin();k!=v.end();k++)
    {
        if (k->second>r)
        {
            l=max(r,k->first);
            r=k->second;
            cover(l,r);
        }
    }
    printf("%.12lf\n",ans);
}
View Code

 

posted @ 2013-09-24 13:23  qinhang3  阅读(209)  评论(0编辑  收藏  举报