HDU 3814 Signal Coverage

给一条直线和多个简单多边形,求在多边形内(包括边上)的线段长度占总长度的百分比。

 

WA了一晚上和一上午换了N种方法终于想到了个简单又好写不用各种讨论无视各种trick的方法。

核心思想就是把线段根据交点分成若干段,然后判断每段的某一边是否有面积。

那这个怎么判断呢?

如上图:不告诉你具体的多边形情况,只知道多边形的边与线段相交的情况,能判断出哪些是区域是多边形内,哪些是外面的么?

很简单的啦,交替就行了,如下图:

具体做法么就是把交点都求出来,并记录这个交点在线段的两边各产生了几条线(多边形的边的某个端点在线段上会在某一边产生一条线,普通的相交会在两边都产生线,重合的就无视掉吧),排个序,相同的点都合并起来。

求长度么就是扫一遍,看到目前这个点为止在线段的两边各已出现多少线,只要有一边是奇数个,那接下去的一段区域就在某个多边形内了。

那线段的起点是否在多边形内呢?反向延长到足够远处,从哪里开始一路判断过来就好了。

 

 

 

#include<iostream>
#include<algorithm>
#include<cmath>
#define eps 1e-9
using namespace std;
double f_abs(double x){
    return x<0?-x:x;
}
struct Point{
    double x,y;
    bool up,dn;
    void disp(){
        printf("%lf %lf\n",x,y);
    }
    void get(){
        scanf("%lf%lf",&x,&y);
    }
    bool friend operator<(Point a,Point b){
        if(f_abs(a.x-b.x)<eps)return a.y<b.y;
        return a.x<b.x;
    }
    bool friend operator>(Point a,Point b){
        return b<a;
    }
    bool friend operator==(Point a,Point b){
        return f_abs(a.x-b.x)<eps&&f_abs(a.y-b.y)<eps;
    }
};
struct Line{
    Point s,e;
    bool friend operator<(Line a,Line b){
        return a.s<b.s;
    }
    void st(){
        Point t;
        if(s>e){
            t=s;s=e;e=t;
        }
    }
    void get(){
        s.get();e.get();
        st();
    }
};
Line line[200000],myl[2];
Point ep[200000];
int en;
double get_cross(Point a,Line b){
    double ax,ay,bx,by;
    ax=b.s.x-a.x;
    ay=b.s.y-a.y;
    bx=b.e.x-a.x;
    by=b.e.y-a.y;
    return ax*by-ay*bx;
}
int inter(Line a,Line b,Point &rp=Point()){//0:不相交 1:相交 2、3:端点相交,a在b某一边 4:重合
    double cj[2];
    cj[0]=get_cross(b.s,a);cj[1]=get_cross(b.e,a);
    if(cj[0]*cj[1]>eps)return 0;
    cj[0]=get_cross(a.s,b);cj[1]=get_cross(a.e,b);
    if(cj[0]*cj[1]>eps)return 0;
    if(f_abs(cj[0])<eps&&f_abs(cj[1])<eps){
        return 4;
    }
    if(f_abs(cj[0])<eps){
        rp=a.s;
        if(cj[1]>eps)return 2;
        else return 3;
    }else if(f_abs(cj[1])<eps){
        rp=a.e;
        if(cj[0]>eps)return 2;
        else return 3;
    }else{
        double key1=(a.e.x-a.s.x)*(b.e.y-b.s.y);  
        double key2=(b.e.x-b.s.x)*(a.e.y-a.s.y);  
        double key=key1-key2;  
        rp.x=(a.s.y-b.s.y)*(a.e.x-a.s.x)*(b.e.x-b.s.x);  
        rp.x-=key2*a.s.x-key1*b.s.x;  
        rp.x/=key;  
        if(f_abs(b.e.x-b.s.x)<eps)rp.y=(a.e.y-a.s.y)/(a.e.x-a.s.x)*(rp.x-a.s.x)+a.s.y;  
        else rp.y=(b.e.y-b.s.y)/(b.e.x-b.s.x)*(rp.x-b.s.x)+b.s.y;  
        return 1;
    }
}
int ln;
void get_myl2(){
    double dy=myl[0].e.y-myl[0].s.y,dx=myl[0].e.x-myl[0].s.x;
    double t=sqrt(dy*dy+dx*dx);
    dy/=t;dx/=t;
    myl[1].e=myl[0].s;
    myl[1].s.x=myl[1].e.x-300000*dx;
    myl[1].s.y=myl[1].e.y-300000*dy;
}
void get_data(){
    myl[0].get();
    int t,n,i;
    int pcnt=0;
    Point p[2],ini;
    ln=0;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        ini.get();
        if(n==1)continue;
        p[0]=ini;
        bool f=0;
        for(i=1;i<n;i++){
            f^=1;
            p[f].get();
            line[ln].s=p[f^1];
            line[ln].e=p[f];
            line[ln++].st();
        }
        line[ln].s=p[f];
        line[ln].e=ini;
        line[ln++].st();
    }
    get_myl2();
}
double get_len(Point a,Point b){
    return sqrt((b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y));
}
void get_ep(Line l){
    en=0;
    int t,i;
    for(i=0;i<ln;i++){
        t=inter(line[i],l,ep[en]);
        if(!t||t==4)continue;
        if(t==1){
            ep[en].up=1;
            ep[en++].dn=1;
        }else if(t==2){
            ep[en].up=1;
            ep[en++].dn=0;
        }else{
            ep[en].up=0;
            ep[en++].dn=1;
        }
    }
    sort(ep,ep+en);
    int ten=0;
    for(i=0;i<en;i++){
        if(ten&&ep[i]==ep[ten-1]){
            ep[ten-1].up^=ep[i].up;
            ep[ten-1].dn^=ep[i].dn;
        }else ep[ten++]=ep[i];
    }
    en=ten;
}
void run(){
    if(myl[0].s==myl[0].e){
        printf("0.00%%\n");
        return;
    }
    int i;
    bool in=0,left=0,right=0;
    get_ep(myl[1]);
    for(i=0;i<en;i++){
		left^=ep[i].up;
		right^=ep[i].dn;
    }
	if(left||right)in=1;
	else in=0;
    get_ep(myl[0]);
    double len=get_len(myl[0].s,myl[0].e),res=0;
    Point lp=myl[0].s;
    ep[en++]=myl[0].e;
    for(i=0;i<en;i++){
        if(ep[i]==myl[0].s)continue;
        if(in)res+=get_len(ep[i],lp);
		left^=ep[i].up;
		right^=ep[i].dn;
        if(left||right)in=1;
		else in=0;
        lp=ep[i];
    }
    printf("%.2lf%%\n",res*100/len);
}
int main(){
    int i,t;
    scanf("%d",&t);
    for(i=1;i<=t;i++){
        get_data();
        printf("Case %d: ",i);
        run();
    }
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值