题意:多边形(可凹可凸)为雷区,雷区边上或外面有两点A,B,问从A到B且不经过雷区里面(可以在边上)的最短距离。
题解:多边形至多有100个点,加上A,B共102个点,任意连线,判断这个线段是否经过多边形内部,将那些不经过内部的线段加入到图中,最后求A到B的最短路。
1 #include<cstdlib> 2 #include<cmath> 3 #include<cstring> 4 #include<cstdio> 5 #include<algorithm> 6 #define max(a,b) (((a)>(b))?(a):(b)) 7 #define min(a,b) (((a)>(b))?(b):(a)) 8 #define sign(x) ((x)>eps?1:((x)<-eps?(-1):(0))) 9 using namespace std; 10 const int N=200; 11 const double eps=1e-8,inf=1e50; 12 struct point 13 { 14 double x,y; 15 point(){} 16 point(double _x,double _y){x=_x;y=_y;} 17 bool operator==(const point &ne)const 18 { 19 return sign(x-ne.x)==0&&sign(y-ne.y)==0; 20 } 21 }; 22 struct line 23 { 24 point a,b; 25 line(){} 26 line(point _a,point _b){a=_a;b=_b;} 27 }; 28 inline double xmult(point o,point a,point b) 29 { 30 return (a.x-o.x)*(b.y-o.y)-(b.x-o.x)*(a.y-o.y); 31 } 32 double x_mult(point sp, point ep, point op){ 33 return (sp.x-op.x)*(ep.y-op.y)-(sp.y-op.y)*(ep.x-op.x); 34 } 35 inline double xmult(double x1,double y1,double x2,double y2) 36 { 37 return x1*y2-x2*y1; 38 } 39 int head[N],nc; 40 struct Edge 41 { 42 int to,next; 43 double cost; 44 }edge[N*N]; 45 double dist[N]; 46 void add(int a,int b,double c) 47 { 48 edge[nc].to=b;edge[nc].next=head[a];edge[nc].cost=c;head[a]=nc++; 49 edge[nc].to=a;edge[nc].next=head[b];edge[nc].cost=c;head[b]=nc++; 50 } 51 bool seg_inter(line s,line p,int e) 52 { 53 double minx1=min(s.a.x,s.b.x),maxx1=max(s.a.x,s.b.x); 54 double minx2=min(p.a.x,p.b.x),maxx2=max(p.a.x,p.b.x); 55 double miny1=min(s.a.y,s.b.y),maxy1=max(s.a.y,s.b.y); 56 double miny2=min(p.a.y,p.b.y),maxy2=max(p.a.y,p.b.y); 57 if((minx1>maxx2+eps)||(minx2>maxx1+eps)|| 58 (miny1>maxy2+eps)||(miny2>maxy1+eps)) 59 return 0; 60 else 61 return sign(xmult(s.a,s.b,p.a)*xmult(s.a,s.b,p.b))<=e&&sign(xmult(p.a,p.b,s.a)*xmult(p.a,p.b,s.b))<=e; 62 } 63 inline int p_on_seg(point a,point p1,point p2) 64 { 65 if(fabs(xmult(a,p1,p2))<=eps&&(a.x-p1.x)*(a.x-p2.x)<eps&&(a.y-p1.y)*(a.y-p2.y)<eps) 66 return 1; 67 return 0; 68 } 69 inline int p_on_segvex(point s,point p) 70 { 71 return fabs(p.y-s.y)<eps&&(p.x<=s.x+eps); 72 } 73 inline int p_in_polygon(point a,point p[],int n) 74 { 75 int count = 0; 76 line s,ps; 77 ps.a = a,ps.b = a; 78 ps.b.x = inf; 79 for(int i = 0; i < n; i++) 80 { 81 s.a = p[i]; 82 if(i + 1 < n)s.b = p[i+1]; 83 else s.b = p[0]; 84 if (s.a.y > s.b.y)swap(s.a,s.b); 85 if (p_on_seg(a,s.a,s.b))return 2; 86 if (fabs(s.a.y-s.b.y)>eps) 87 { 88 if (p_on_segvex(s.b,a)) count++; 89 else if (seg_inter(ps,s,-1))count++; 90 } 91 } 92 if (count%2)return 1; 93 return 0; 94 } 95 inline double getdist(point a,point b) 96 { 97 return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); 98 } 99 bool comp(point a,point b) 100 { 101 if(fabs(a.x-b.x)>eps) 102 return a.x<b.x; 103 else 104 return a.y<b.y; 105 } 106 point line_intersection(line u,line v) 107 { 108 double a1=u.b.y-u.a.y,b1=u.a.x-u.b.x; 109 double c1=u.b.y*(-b1)-u.b.x*a1; 110 double a2=v.b.y-v.a.y,b2=v.a.x-v.b.x; 111 double c2=v.b.y*(-b2)-v.b.x*a2; 112 double D=xmult(a1,b1,a2,b2); 113 return point(xmult(b1,c1,b2,c2)/D,xmult(c1,a1,c2,a2)/D); 114 } 115 bool check(line s,point pg[],int n) 116 { 117 point inter[N]; 118 int top=0; 119 for(int i=0;i<n;i++) 120 if(seg_inter(s,line(pg[i],pg[i+1]),0)) 121 { 122 int ta=sign(xmult(s.a,s.b,pg[i])),tb=sign(xmult(s.a,s.b,pg[i+1])); 123 if(ta==0&&tb==0) 124 continue; 125 if(ta==0||tb==0) 126 inter[top++]=line_intersection(line(pg[i],pg[i+1]),s); 127 else if(seg_inter(s,line(pg[i],pg[i+1]),-1)) 128 return false; 129 } 130 sort(inter, inter+top, comp); 131 for(int i=0;i<top-1;i++) 132 { 133 point mid((inter[i].x+inter[i+1].x)/2.0,(inter[i].y+inter[i+1].y)/2.0); 134 bool flag=true; 135 for(int j=0;j<n;j++) 136 if(p_on_seg(mid,pg[j],pg[j+1])) 137 { 138 flag=false; 139 break; 140 } 141 if(flag&&p_in_polygon(mid,pg,n)&&getdist(inter[i],inter[i+1])>eps) 142 return false; 143 } 144 return true; 145 } 146 double dijkstra(int s,int t) 147 { 148 bool vis[N]; 149 memset(vis, false, sizeof(vis)); 150 dist[s]=0; 151 for(int i=0;i<=t;i++) 152 { 153 double mm=inf; 154 int k=0; 155 for(int j=0;j<=t;j++) 156 if(!vis[j]&&dist[j]<mm) 157 mm=dist[k=j]; 158 if(k==t) 159 return dist[t]; 160 vis[k]=true; 161 for(int j=head[k];j!=-1;j=edge[j].next) 162 { 163 dist[edge[j].to]=min(dist[edge[j].to],dist[k]+edge[j].cost); 164 } 165 } 166 } 167 int main() 168 { 169 int n; 170 point a,b; 171 while(scanf("%lf%lf%lf%lf",&a.x,&a.y,&b.x,&b.y)!=EOF) 172 { 173 scanf("%d",&n); 174 nc=0; 175 memset(head,-1,sizeof(head)); 176 point pg[N]; 177 for(int i=0;i<n;i++) 178 scanf("%lf%lf",&pg[i].x,&pg[i].y); 179 pg[n]=pg[0]; 180 if(check(line(a,b),pg,n)) 181 { 182 printf("%.4lf\n",getdist(a,b)); 183 continue; 184 } 185 int S=0,T=n+1; 186 for(int i=0;i<n;i++) 187 { 188 dist[i]=inf; 189 if(check(line(a,pg[i]),pg,n)) 190 add(S,i+1,getdist(a,pg[i])); 191 if(check(line(pg[i],b),pg,n)) 192 add(i+1,T,getdist(b,pg[i])); 193 for(int j=i+1;j<n;j++) 194 if(check(line(pg[i],pg[j]),pg,n)) 195 add(i+1,j+1,getdist(pg[i],pg[j])); 196 } 197 dist[n]=dist[n+1]=inf; 198 printf("%.4lf\n",dijkstra(S,T)); 199 } 200 return 0; 201 }