题意:
一个正方形中有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 }