POJ 1556 The Doors(判断线段相交 && 最短路)
2015-08-29 00:12
405 查看
The Doors
DescriptionYou 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;
}
相关文章推荐
- POJ 1556 The Doors(判断线段相交 && 最短路)
- EF性能优化(C# 版 潘鹏)
- 剑指Offer-二叉树的镜像
- Java多态 实例子类自动调用父类为空的构造方法 成员变量不支持Override 可写,没多态效果
- 【java-日志组件】slf4j+logback配置及详解
- 剑指Offer-树的子结构
- 剑指Offer-数值的整数次方
- 第一百四十八天 how can I坚持
- Cocos2d-x内存管理-绕不过去的坎
- 剑指Offer-用两个栈实现队列
- postMessage解决跨域下跨文档通信
- scala中的self type
- 【2015拼客科技PingingLab校招战报】逆天?3枚腾讯offer入手!来看看他们都是谁?
- Java集合之HashMap
- Java集合之HashMap
- Springmvc集成Shiro实现权限管理
- Java-HashMap源码分析及示例
- 接口IIC_SPI_URAT_USB_can
- HPU 2686--Matrix【最大费用最大流 && 经典建图】
- 最小美观程度