POJ1556 The Doors(线段与线段相交,Dijkstra)

题目链接:

  http://poj.org/problem?id=1556

题目描述:

The Doors
 

Description

You are to find the length of the shortest path through a chamber containing obstructing walls. The chamber will always have sides at x = 0, x = 10, y = 0, and y = 10. The initial and final points of the path are always (0, 5) and (10, 5). There will also be from 0 to 18 vertical walls inside the chamber, each with two doorways. The figure below illustrates such a chamber and also shows the path of minimal length. 

Input

The input data for the illustrated chamber would appear as follows. 


4 2 7 8 9 
7 3 4.5 6 7 

The first line contains the number of interior walls. Then there is a line for each such wall, containing five real numbers. The first number is the x coordinate of the wall (0 < x < 10), and the remaining four are the y coordinates of the ends of the doorways in that wall. The x coordinates of the walls are in increasing order, and within each line the y coordinates are in increasing order. The input file will contain at least one such set of data. The end of the data comes when the number of walls is -1. 

Output

The output should contain one line of output for each chamber. The line should contain the minimal path length rounded to two decimal places past the decimal point, and always showing the two decimal places past the decimal point. The line should contain no blanks.

Sample Input

1
5 4 6 7 8
2
4 2 7 8 9
7 3 4.5 6 7
-1

Sample Output

10.00
10.06

题目大意:

  给定一块(0,0)与(10,10)之间的区域,中间有垂直的挡板,问从(0,5)到(10,5)的最短路径

思路:

  把起点终点和各挡板端点作为顶点建图,对点之间两两建线段,判断是否与挡板(线段)有交点,若无交点则建一条有向边,最后Dijkstra求最短路

代码:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <cmath>
  6 #include <queue>
  7 #include <utility>
  8 #include <functional>
  9 using namespace std;
 10 
 11 typedef pair<double, int> pii;
 12 
 13 const int INF = 0x3f3f3f3f;
 14 const int N = 10010;
 15 
 16 const double EPS = 1e-10;    //精度系数
 17 
 18 struct Edge {
 19     int v, next;
 20     double val;
 21     Edge(int v = 0, double val = 0, int next = 0) :v(v), val(val), next(next) {}
 22 }e[N];
 23 
 24 struct Point {
 25     double x, y;
 26     Point(double x = 0, double y = 0) :x(x), y(y) {}
 27 };    //点的定义
 28 
 29 typedef Point Vector;    //向量的定义
 30 
 31 Vector operator - (Vector A, Vector B) { return Vector(A.x - B.x, A.y - B.y); }    //向量减法
 32 
 33 int head[N], id, ED;
 34 bool vis[N];
 35 Point P[N];
 36 double x[N], y[N][4], d[N];
 37 
 38 inline void addedge(int u, int v, double val) {
 39     e[++id].v = v;
 40     e[id].val = val;
 41     e[id].next = head[u];
 42     head[u] = id;
 43 }
 44 
 45 void Dijkstra_heap(int s) {
 46     priority_queue<pii, vector<pii>, greater<pii> > Q;
 47     for (int i = 0; i <= ED; ++i)d[i] = INF;
 48     d[s] = 0;
 49     memset(vis, false, sizeof(vis));
 50     Q.push(make_pair(d[s], s));
 51     while (!Q.empty()) {
 52         pii tmp = Q.top();
 53         Q.pop();
 54         int x = tmp.second;
 55         if (vis[x]) continue;
 56         vis[x] = true;
 57         if (x == ED)return;
 58         for (int i = head[x]; i; i = e[i].next)
 59             if (d[e[i].v] > d[x] + e[i].val) {
 60                 d[e[i].v] = d[x] + e[i].val;
 61                 Q.push(make_pair(d[e[i].v], e[i].v));
 62             }
 63     }
 64 }
 65 
 66 int dcmp(double x) {
 67     if (fabs(x) < EPS)return 0; else return x < 0 ? -1 : 1;
 68 }    //与0的关系
 69 
 70 double Cross(Vector A, Vector B) { return A.x*B.y - A.y*B.x; }    //向量叉乘
 71 
 72 bool SegmentProperIntersection(Point a1, Point a2, Point b1, Point b2) {
 73     double c1 = Cross(a2 - a1, b1 - a1), c2 = Cross(a2 - a1, b2 - a1),
 74         c3 = Cross(b2 - b1, a1 - b1), c4 = Cross(b2 - b1, a2 - b1);
 75     return dcmp(c1)*dcmp(c2) < 0 && dcmp(c3)*dcmp(c4) < 0;
 76 }    //判断两线段相交(恰有一个公共点且不在端点)
 77 
 78 double Dis(Point& a, Point& b) {
 79     return sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
 80 }    //两点距离
 81 
 82 bool ok(int k, int m, int t) {
 83     double l = P[k].x, r = P[m].x;
 84     for (int i = 0; i < t; ++i)if (l < x[i] && x[i] < r) {
 85         bool flag = false;
 86         flag |= SegmentProperIntersection(P[k], P[m], Point(x[i], 0), Point(x[i], y[i][0]));
 87         flag |= SegmentProperIntersection(P[k], P[m], Point(x[i], y[i][1]), Point(x[i], y[i][2]));
 88         flag |= SegmentProperIntersection(P[k], P[m], Point(x[i], y[i][3]), Point(x[i], 10));
 89         if (flag)return false;
 90     }
 91     return true;
 92 }    //两点之间是否有线段
 93 
 94 int main() {
 95     int n;
 96     while (cin >> n && n != -1) {
 97         memset(head, 0, sizeof(head));
 98         id = 0;
 99         ED = 4 * n + 1;
100         P[0] = Point(0, 5);
101         P[ED] = Point(10, 5);
102         for (int i = 0; i < n; ++i) {
103             scanf("%lf", &x[i]);
104             for (int j = 0; j < 4; ++j) {
105                 int m = 4 * i + j + 1;
106                 scanf("%lf", &y[i][j]);
107                 P[m].x = x[i], P[m].y = y[i][j];
108                 for (int k = 0; k < 4 * i + 1; ++k)    //判断之前的点到当前点是否有边
109                     if (ok(k, m, i))addedge(k, m, Dis(P[k], P[m]));
110             }
111         }
112         for (int k = 0; k < 4 * n + 1; ++k)    //判断之前的点到终点是否有边
113             if (ok(k, ED, n))addedge(k, ED, Dis(P[k], P[ED]));
114         Dijkstra_heap(0);    //Dijkstra求最短路
115         printf("%.2lf\n", d[ED]);
116     }
117 }

 

posted @ 2017-06-13 08:01  hyp1231  阅读(271)  评论(0编辑  收藏  举报