和图论中的最短路密切相关的一道题目,把所有的线段端点看做一个无向图中的顶点,两个顶点如果能够通过线段连接(需要判断线段相交,经典的计算几何基础),则路径长度为线段长度,否则置为无穷大。在构造的图上运行最短路算法就可以了(Dijkstra算法就行,不过floyd算法更容易实现,尽管复杂度略高。)
#include <vector> #include <list> #include <limits.h> #include <map> #include <set> #include <deque> #include <queue> #include <stack> #include <bitset> #include <algorithm> #include <functional> #include <numeric> #include <utility> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cmath> #include <cstdlib> #include <ctime> #include <string.h> #include <stdlib.h> #include <cassert> using namespace std; struct Point { double x, y; Point(double _x, double _y): x(_x), y(_y) {} Point() {} }; struct Line { Point p1, p2; Line(Point _p1, Point _p2): p1(_p1), p2(_p2) {} Line() {} }; double cross(Point a, Point b1, Point b2) { return (b1.x - a.x) * (b2.y - a.y) - (b1.y - a.y) * (b2.x - a.x); } bool intersect(Line a, Line b) { Point pa1 = a.p1, pa2 = a.p2; Point pb1 = b.p1, pb2 = b.p2; return max(pa1.x, pa2.x) > min(pb1.x, pb2.x) && max(pb1.x, pb2.x) > min(pa1.x, pa2.x) && max(pa1.y, pa2.y) > min(pb1.y, pb2.y) && max(pb1.y, pb2.y) > min(pa1.y, pa2.y) && cross(pa1, pa2, pb1) * cross(pa1, pa2, pb2) < 0 && cross(pb1, pb2, pa1) * cross(pb1, pb2, pa2) < 0; } double euclidean(Point p1, Point p2) { return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)); } vector<Line> v; vector<Point> ps; const int MAX_N = 80; double dis[MAX_N][MAX_N]; int main() { int N, M; while (cin >> N && N >= 0) { v.clear(); ps.clear(); ps.push_back(Point(0, 5)); ps.push_back(Point(10, 5)); double x, y; Point p[4]; for (int i = 0; i < N; ++i) { cin >> x; for (int j = 0; j < 4; ++j) { cin >> y; p[j] = Point(x, y); ps.push_back(Point(x, y)); } v.push_back(Line(Point(x, 0), p[0])); v.push_back(Line(p[1], p[2])); v.push_back(Line(p[3], Point(x, 10))); } int T = ps.size(); for (int i = 0; i < T; ++i) for (int j = 0; j < T; ++j) { if (i == j) dis[i][j] = 0; else dis[i][j] = INT_MAX; } for (int i = 0; i < T; ++i) for (int j = 0; j < i; ++j) { Line l(ps[i], ps[j]); bool ok = true; for (int k = 0; k < v.size(); ++k) { if (intersect(v[k], l)) { ok = false; break; } } if (ok) { dis[i][j] = min(dis[i][j], euclidean(ps[i], ps[j])); dis[j][i] = min(dis[j][i], euclidean(ps[i], ps[j])); } } // floyd is easier to implement for (int k = 0; k < T; ++k) for (int i = 0; i < T; ++i) for (int j = 0; j < T; ++j) { dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]); } cout << fixed << setprecision(2) << dis[0][1] << endl; } return 0; }