給一條直線和多個簡單多邊形,求在多邊形內(包括邊上)的線段長度佔總長度的百分比。
WA了一晚上和一上午換了N種方法終於想到了個簡單又好寫不用各種討論無視各種trick的方法。
核心思想就是把線段根據交點分成若干段,然後判斷每段的某一邊是否有面積。
那這個怎麼判斷呢?
如:不告訴你具體的多邊形情況,只知道多邊形的邊與線段相交的情況,能判斷出哪些是地區是多邊形內,哪些是外面的嗎?
很簡單的啦,交替就行了,如:
具體做法麼就是把交點都求出來,並記錄這個交點線上段的兩邊各產生了幾條線(多邊形的邊的某個端點線上段上會在某一邊產生一條線,普通的相交會在兩邊都產生線,重合的就無視掉吧),排個序,相同的點都合并起來。
求長度麼就是掃一遍,看到目前這個點為止線上段的兩邊各已出現多少線,只要有一邊是奇數個,那接下去的一段地區就在某個多邊形內了。
那線段的起點是否在多邊形內呢?反向延長到足夠遠處,從哪裡開始一路判斷過來就好了。
#include<iostream>#include<algorithm>#include<cmath>#define eps 1e-9using 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;}