POJ (线段相交 最短路) The Doors

题意:

一个正方形中有n道竖直的墙,每道墙上开两个门。求从左边中点走到右边中点的最短距离。

分析:

以起点终点和每个门的两个端点建图,如果两个点可以直接相连(即不会被墙挡住),则权值为两点间的欧几里得距离。

然后求起点到终点的最短路即可。

  1 #include <cstdio>
  2 #include <cmath>
  3 #include <cstring>
  4 #include <vector>
  5 #include <algorithm>
  6 using namespace std;
  7 
  8 const int maxn = 50;
  9 const double INF = 1e4;
 10 const double eps = 1e-8;
 11 
 12 struct Point
 13 {
 14     double x, y;
 15     Point(double x=0, double y=0):x(x), y(y) {}
 16 }p[maxn * 4];
 17 
 18 typedef Point Vector;
 19 
 20 Point read_point()
 21 {
 22     double x, y;
 23     scanf("%lf%lf", &x, &y);
 24     return Point(x, y);
 25 }
 26 
 27 Point operator - (const Point& A, const Point& B)
 28 { return Point(A.x-B.x, A.y-B.y); }
 29 
 30 Vector operator / (const Vector& A, double p)
 31 { return Vector(A.x/p, A.y/p); }
 32 
 33 double Dot(const Vector& A, const Vector& B)
 34 { return A.x*B.x + A.y*B.y; }
 35 
 36 double Length(const Vector& A)
 37 { return sqrt(Dot(A, A)); }
 38 
 39 struct Door
 40 {
 41     double x, y1, y2, y3, y4;
 42     Door(double x=0, double y1=0, double y2=0, double y3=0, double y4=0):x(x), y1(y1), y2(y2), y3(y3), y4(y4) {}
 43 };
 44 
 45 vector<Door> door;
 46 
 47 double d[maxn * 4], w[maxn * 4][maxn * 4];
 48 bool vis[maxn * 4];
 49 int cnt;
 50 
 51 bool isOK(int a, int b)
 52 {//判断两点是否能直接到达
 53     if(p[a].x >= p[b].x) swap(a, b);
 54     for(int i = 0; i < door.size(); ++i)
 55     {
 56         if(door[i].x <= p[a].x) continue;
 57         if(door[i].x >= p[b].x) break;
 58         double k = (p[b].y-p[a].y) / (p[b].x-p[a].x);
 59         double y = p[a].y + k * (door[i].x - p[a].x);
 60         if(!(y>=door[i].y1&&y<=door[i].y2 || y>=door[i].y3&&y<=door[i].y4)) return false;
 61     }
 62     return true;
 63 }
 64 
 65 void Init()
 66 {
 67     for(int i = 0; i < cnt; ++i)
 68         for(int j = i; j < cnt; ++j)
 69             if(i == j) w[i][j] = 0;
 70             else w[i][j] = w[j][i] = INF;
 71 }
 72 
 73 int main()
 74 {
 75     //freopen("in.txt", "r", stdin);
 76 
 77     int n;
 78     while(scanf("%d", &n) == 1 && n + 1)
 79     {
 80         door.clear();
 81         memset(vis, false, sizeof(vis));
 82         memset(d, 0, sizeof(d));
 83 
 84         p[0] = Point(0, 5);
 85         cnt = 1;
 86         for(int i = 0; i < n; ++i)
 87         {
 88             double x, y[4];
 89             scanf("%lf", &x);
 90             for(int j = 0; j < 4; ++j) { scanf("%lf", &y[j]); p[cnt++] = Point(x, y[j]); }
 91             door.push_back(Door(x, y[0], y[1], y[2], y[3]));
 92         }
 93         p[cnt++] = Point(10, 5);
 94 
 95         Init();
 96 
 97         for(int i = 0; i < cnt; ++i)
 98             for(int j = i+1; j < cnt; ++j)
 99             {
100                 double l = Length(Vector(p[i]-p[j]));
101                 if(p[i].x == p[j].x) continue;
102                 if(isOK(i, j))
103                     w[i][j] = w[j][i] = l;
104             }
105         //Dijkstra
106         d[0] = 0;
107         for(int i = 1; i < cnt; ++i) d[i] = INF;
108         for(int i = 0; i < cnt; ++i)
109         {
110             int x;
111             double m = INF;
112             for(int y = 0; y < cnt; ++y) if(!vis[y] && d[y] <= m) m = d[x=y];
113             vis[x] = 1;
114             for(int y = 0; y < cnt; ++y) d[y] = min(d[y], d[x] + w[x][y]);
115         }
116 
117         printf("%.2f
", d[cnt-1]);
118     }
119 
120     return 0;
121 }
代码君
原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/4272796.html