题意:多边形(可凹可凸)为雷区,雷区边上或外面有两点A,B,问从A到B且不经过雷区里面(可以在边上)的最短距离。

题解:多边形至多有100个点,加上A,B共102个点,任意连线,判断这个线段是否经过多边形内部,将那些不经过内部的线段加入到图中,最后求A到B的最短路。

View Code
  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 }