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\n", d[cnt-1]);

118     }

119 

120     return 0;

121 }
代码君

 

你可能感兴趣的:(poj)