您的位置:首页 > 其它

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

2015-08-29 00:12 405 查看

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
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

【思路分析】

   这个题目有意思之处在于将计算几何和图论的问题巧妙地结合起来。题意大概是在一个图中给你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 150
double 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: