POJ 2966

题意:多边形(可凹可凸)为雷区,雷区边上或外面有两点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 }

你可能感兴趣的:(poj)