POJ 1556 The Doors(判断线段相交 && 最短路)

来源:互联网 发布:安卓简单捕鱼源码 编辑:程序博客网 时间:2024/04/30 12:16

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.

2
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

15 4 6 7 824 2 7 8 97 3 4.5 6 7-1

Sample Output

10.0010.06

【思路分析】

   这个题目有意思之处在于将计算几何和图论的问题巧妙地结合起来。题意大概是在一个图中给你4 * n + 1个点,其中有一个起点,一个终点以及每一列的四个点,每一列的四个点又构成了三个线段,即隔墙,要求起点到终点的最短路径(当然该路径不能“穿墙”)。该题最关键的就是建图,通过判断两点之间构成的路径是否和隔墙相交来在邻接矩阵中键入权值(即两点之间的路径),要注意的是这里的线段相交要忽视两线段有一个公共端点的情况,即考虑“擦墙而过”,所以两线段不相交时在邻接矩阵中相应位置键入两点之间的距离,若两线段相交则表示此路不通,键入一个无穷大值。当建图好之后就是找最短路了。


代码如下:

#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#include <algorithm>using namespace std;#define eps 1e-8#define inf 1e20#define maxn 150double maps[maxn][maxn];double dis[maxn],visited[maxn];int n;struct Point{    double x,y;    Point()    {    }    Point(double x1,double y1)    {        x = x1;        y = y1;    }    Point operator - (const Point &b) const    {        return Point(x - b.x,y - b.y);    }    double operator ^ (const Point &b) const    {        return x * b.y - y * b.x;    }    double operator * (const Point &b) const    {        return x * b.x + y * b.y;    }}points[maxn];struct Line{    Point s,e;    Line()    {    }    Line(Point s1,Point e1)    {        s = s1;        e = e1;    }}lines[maxn];int sgn(double x){    if(fabs(x) < eps)        return 0;    if(x < 0)        return -1;    return 1;}double distances(Point p1,Point p2){    return sqrt((p2 - p1) * (p2 - p1));}bool intersection(Line l1,Line l2){    return    max(l1.s.x,l1.e.x) >= min(l2.s.x,l2.e.x) &&    max(l1.s.y,l1.e.y) >= min(l2.s.y,l2.e.y) &&    max(l2.s.x,l2.e.x) >= min(l1.s.x,l1.e.x) &&    max(l2.s.y,l2.e.y) >= min(l1.s.y,l1.e.y) &&    sgn((l2.s - l1.e) ^ (l1.s - l1.e)) * sgn((l2.e - l1.e) ^ (l1.s - l1.e)) < 0 &&    sgn((l1.s - l2.e) ^ (l2.s - l2.e)) * sgn((l1.e - l2.e) ^ (l2.s - l2.e)) < 0;    //注意此处是小于0,即忽视两个线段有一个公共端点的相交情况!}void init(){    points[0] = Point(0,5);    for(int i = 1;i <= n;i++)    {        double x;        scanf("%lf %lf %lf %lf %lf",&x,&points[i].y,&points[i + n].y,&points[i + n * 2].y,&points[i + n * 3].y);        points[i].x = points[i + n].x = points[i + n * 2].x = points[i + n * 3].x = x;        lines[i] = Line(Point(x,0),points[i]);        lines[i + n] = Line(points[i + n],points[i + n * 2]);        lines[i + n * 2] = Line(points[i + n * 3],Point(x,10));    }    points[n * 4 + 1] = Point(10,5);    bool flag = true;    for(int i = 0;i <= n * 4 + 1;i++)//起点、终点加上每一列的4个点    {        for(int j = 0;j <= n * 4 + 1;j++)        {            flag = true;            for(int k = 1;k <= 3 * n;k++)//每列三条线段            {                if(intersection(Line(points[i],points[j]),lines[k]))                {                    flag = false;                    break;                }            }            if(flag == true)//两线段不相交            {                maps[i][j] = distances(points[i],points[j]);            }            else            {                maps[i][j] = inf;            }        }    }}double dijkstra(int s,int t){    for(int i = 0;i <= n * 4 + 1;i++)    {        dis[i] = maps[s][i];        visited[i] = 0;    }    dis[s] = 0;    visited[s] = 1;    int temp,k = s;    for(int i = 1;i <= n * 4 + 1;i++)    {        temp = inf;        for(int j = 0;j <= n * 4 + 1;j++)        {            if(visited[j] == 0 && temp > dis[j])            {                k = j;                temp = dis[j];            }        }        if(temp == inf)            break;        visited[k] = 1;        for(int j = 0;j <= n * 4 + 1;j++)        {            if(dis[j] > dis[k] + maps[k][j])                dis[j] = dis[k] + maps[k][j];        }    }    return dis[t];}int main(){    while(scanf("%d",&n) != EOF && n != -1)    {        init();        printf("%.2lf\n",dijkstra(0,n * 4 + 1));    }    return 0;}


0 0
原创粉丝点击