The Doors
Description

Input
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
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;
}
373



被折叠的 条评论
为什么被折叠?



