sgu 129 Inheritance 凸包,线段交点,计算几何 难度:2


129. Inheritance

time limit per test: 0.25 sec. 
memory limit per test: 4096 KB

 

The old King decided to divide the Kingdom into parts among his three sons. Each part is a polygonal area. Taking into account the bad temper of the middle son the King gave him a part of Kingdom such that moving straight from any place of this part to any other place of this part he will not cross the boundary.
There are several mineral deposits in the Kingdom. Each mineral deposit looks like a straight line segment. The middle son wants to know what part of mineral deposits is located inside his territory (not including the boundaries).

 

Input

The first line contains an integer N (3<=N<=400) - the number of vertexes of the polygon boundaring the territory of King's middle son. Each i-th line of the next N lines contains pair of integers xi, yi (0<=xi,yi<=30000) - a position of the i-th vertex (3<=i<=400). The vertexes are given in random order. There are no any three vertexes laying on a straight line. The next line includes the only integer M (2<=M<=1000) - the number of mineral deposits in the Kingdom. Each j-th line of the next M lines contains two pairs of integers aj1, bj1 - point of the beginning and aj2, bj2 - point of the end of the j-th mineral deposit (0<=aj1,bj1,aj2,bj2<=30000, for 1<=j<=M). The numbers in each line are divided by spaces.

 

Output

Output file should contain M lines. Each j-th line should contain a real number Lj calculated with precision 0.01 - the lehgth of the middle son's part of j-th mineral deposit.

 

Sample Input

3

1 1

6 1

1 6

4

1 2 1 4

2 2 2 4

4 2 4 4 

6 2 6 4

Sample Output

0

2

1

0

思路很简单,就是涉及到了多个计算几何的知识点
1 领地点都是凸包上的点,需要按照凸包排个序,确定了左下点之后按逆时针排个序就行
2 对于线段,完全列举一下凸包的所有边,看有多少交点即可(一定只有<=2个)
3 对于和凸包有交点的线段,如果两个相邻点的中点在凸包内,那么这俩因为本来就是边界了,所以一定这一段在凸包里,如果没有交点,要是线段中点在凸包内也一样
4 如何判断线段交点?...设线段A=P+t1*v(v是方向向量,P是起点),B=Q+t2*w(w向量,Q起点),u=P-Q,则t1=cross(w,u)/cross(v,w),t2=cross(v,u)/cross(v,w),线段交点要满足t1,t2属于[0,1],满足条件后带入即可
5 如何确定点是否在凸包内?设凸包点集为P,(P按凸包已经排好了,)对于所有的线段p[(i+1)%n],p[i] ,因为P构成了凸包,所以只需要都在左侧即可.(转角法缩略版),画个图看看就懂
注意:使用复数的叉积不知道为什么不行?也许是我的姿势不对
#include <cstdio>

#include <cstring>

#include <algorithm>

#include <cmath>

using namespace std;

const double eps=1e-8;

int dcmp(double d){

    if(fabs(d)<eps)return 0;

    return d>0?1:-1;

}

struct pnt{

    double x,y;

    pnt():x(0),y(0){}

    pnt(double tx,double ty):x(tx),y(ty){}

    pnt operator -(pnt p2){

        pnt newp(x-p2.x,y-p2.y);

        return newp;

    }

    pnt operator +(pnt p2){

        pnt newp(x+p2.x,y+p2.y);

        return newp;

    }

    pnt operator *(double  d){

        pnt newp(x*d,y*d);

        return newp;

    }

    pnt operator /(double  d){

        pnt newp(x/d,y/d);

        return newp;

    }

    double dis(pnt p2){

        return sqrt((x-p2.x)*(x-p2.x)+(y-p2.y)*(y-p2.y));

    }

    bool operator ==(pnt p2){

        if(dcmp(x-p2.x)==0&&dcmp(y-p2.y)==0)return true;

        return false;

    }

};

pnt p[2000],inset[2000][2],seg[2000][2];

int n,m,len[2000];

double cross(pnt p1,pnt p2){

    return p1.x*p2.y-p1.y*p2.x;

}

bool cmpx(pnt p1,pnt p2){

    if(p1.x!=p2.x)return p1.x<p2.x;

    return p1.y<p2.y;

}

bool cmp(pnt p1,pnt p2){

    return cross(p1-p[0],p2-p[0])<0;

}



int isPointInConvexPolygon(pnt p1){

    for(int i=0;i<n;i++){

        pnt A=pnt(p[(i+1)%n].x-p[i].x,p[(i+1)%n].y-p[i].y);

        pnt B=pnt(p1.x-p[i].x,p1.y-p[i].y);

        int fl=dcmp(cross(A,B));

        if(fl>0)return 0;

        if(fl==0){

            int maxx=max(p[(i+1)%n].x,p[i].x);

            int minx=min(p[(i+1)%n].x,p[i].x);

            int maxy=max(p[(i+1)%n].y,p[i].y);

            int miny=min(p[(i+1)%n].y,p[i].y);

            if(minx<=p1.x&&maxx>=p1.x&&miny<=p1.y&&maxy>=p1.y)return -1;

        }

    }

    return 1;

}

void getinsertpoint(){

    for(int i=0;i<n;i++){

        pnt v=p[(i+1)%n]-p[i];

        for(int j=0;j<m;j++){

            pnt w=seg[j][1]-seg[j][0];

            if(dcmp(cross(v,w))==0)continue;

            pnt u=p[i]-seg[j][0];

            double t=cross(w,u)/cross(v,w);

            double t2=cross(v,u)/cross(v,w);

            if(t2+eps>1||t2+eps<0)continue;

            if(t<1+eps&&t+eps>0){

                pnt newp=p[i]+v*t;

                bool fl=true;

                for(int k=0;k<len[j];k++){

                    if(newp==inset[j][k])fl=false;

                }

                if(fl)inset[j][len[j]++]=newp;

            }

        }

    }

}

void getlength(){

    for(int i=0;i<m;i++){

        double leng=0;

        if(len[i]==2){

            pnt mid1=(seg[i][0]+inset[i][0])/2;

            int stamid=isPointInConvexPolygon(mid1);

            if(stamid==1){

                leng+=seg[i][0].dis(inset[i][0]);

            }

            mid1=(inset[i][0]+inset[i][1])/2;

            stamid=isPointInConvexPolygon(mid1);

            if(stamid==1){

                leng+=inset[i][0].dis(inset[i][1]);

            }

            mid1=(seg[i][1]+inset[i][1])/2;

            stamid=isPointInConvexPolygon(mid1);

            if(stamid==1){

                leng+=seg[i][1].dis(inset[i][1]);

            }

        }

        else if(len[i]==1){

            pnt mid1=(seg[i][0]+inset[i][0])/2;

            int stamid=isPointInConvexPolygon(mid1);

            if(stamid==1){

                leng+=seg[i][0].dis(inset[i][0]);

            }

            mid1=(seg[i][1]+inset[i][0])/2;

            stamid=isPointInConvexPolygon(mid1);

            if(stamid==1){

                leng+=seg[i][1].dis(inset[i][0]);

            }

        }

        else if(len[i]==0){

            pnt mid1=(seg[i][1]+seg[i][0])/2;

           int  stamid=isPointInConvexPolygon(mid1);

            if(stamid==1){

                leng+=seg[i][1].dis(seg[i][0]);

            }

        }

        printf("%.2f\n",leng);

    }

}

int main(){

    scanf("%d",&n);

    for(int i=0;i<n;i++){

        scanf("%lf%lf",&p[i].x,&p[i].y);

    }

    scanf("%d",&m);

    for(int i=0;i<m;i++){

        scanf("%lf%lf%lf%lf",&seg[i][0].x,&seg[i][0].y,&seg[i][1].x,&seg[i][1].y);

    }

    for(int i=0;i<m;i++){

        sort(seg[i],seg[i]+2,cmpx);

    }

    sort(p,p+n,cmpx);

    sort(p+1,p+n,cmp);

    getinsertpoint();

    for(int i=0;i<m;i++){

        sort(inset[i],inset[i]+len[i],cmpx);

    }

    getlength();

    return 0;

}

  

你可能感兴趣的:(inheritance)