The Doors
题目来源
HIT1252
POJ1556
UVA393
UVAlive5310
ZOJ1721
题面
描述
你可以在一个包含障碍墙的房间中找到最短的一条路径。房间的边界位于x=0,x=10,y=0,y=10。路径的起始点和终点始终为(0,5)和(10,5)。房间中将有0到18面障碍墙,每一面墙有两个门。下图给出了这样一个房间并标出了房间中的最短路径。
输入
描述房间的输入数据将以以下的形式给出
2
4 2 7 8 9
7 3 4.5 6 7
第一行给出障碍墙的数量。接下来每一行包括五个实数。第一个数是墙的x坐标(0\<\x\<\10),剩下的四个数是门的两端的y坐标。保证x坐标按照增序给出,每一行中的y坐标也按照增序给出。输入文件将包括至少一组数据。数据以障碍墙数量为-1作为结束标志。
输出
对每个房间输出一行。行中应包含最短路径的长度,四舍五入到小数点后两位。行中无空格。
样例
输入
1
5 4 6 7 8
2
4 2 7 8 9
7 3 4.5 6 7
-1
输出
10.00
10.06
???
从第i面墙到第j面墙的最短路径,一定受限于第i到第j面墙中某一面墙的门的端点。
因此最终的最短路径,一定是从起点出发后,每次直线距离到达某面墙的门的端点。
以所有门的端点为顶点建图,将从端点x出发可以直线距离到达的所有顶点y连边,边权即两点的最短距离。
从起点到终点跑最短路。
代码
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN=100;
const int MAXM=10000;
const double eps=1e-10;
int s,t;
int n,m;
bool vis[MAXN];
double val[MAXM],dist[MAXN];
double x[20],y[20][10];
int frst[MAXN],nxt[MAXM],ed[MAXM];
struct Point
{
double x,y;
Point(double x=0,double y=0):x(x),y(y){}
};
typedef Point Vector;
int dcmp(double x)
{
if (fabs(x)<eps)
return 0;
return x>0 ? 1:-1;
}
Vector operator - (Vector A,Vector B)
{
return Vector(A.x-B.x,A.y-B.y);
}
double Cross(Vector A,Vector B)
{
return A.x*B.y-A.y*B.x;
}
bool intersect(Point A,Point B,Point P,Point Q)
{
return dcmp(Cross(Q-P,A-P))*dcmp(Cross(Q-P,B-P))<0;
}
double dis(double a,double b,double c,double d)
{
return sqrt((a-c)*(a-c)+(b-d)*(b-d));
}
void addedge(int a,int b,double s)
{
nxt[++m]=frst[a];
frst[a]=m;
ed[m]=b;
val[m]=s;
}
bool check(int i,double a,int j,double b)
{
Point X=Point(x[i],a),Y=Point(x[j],b);
for (int k=i+1;k<j;k++)
for (int aa=0;aa<=2;aa++)
{
Point A=Point(x[k],y[k][aa*2]),B=Point(x[k],y[k][aa*2+1]);
if (intersect(A,B,X,Y))
return false;
}
return true;
}
int main()
{
while (scanf("%d",&n)==1)
{
m=-1;
memset(frst,-1,sizeof(frst));
if (n==-1)
return 0;
for (int i=1;i<=n;i++)
{
scanf("%lf",&x[i]);
y[i][0]=0;
y[i][5]=10;
for (int j=1;j<=4;j++)
scanf("%lf",&y[i][j]);
}
s=1;
t=n*4+5;
x[0]=0;
x[n+1]=10;
if (check(0,5,n+1,5))
addedge(s,t,10);
for (int i=1;i<=n;i++)
for (int j=1;j<=4;j++)
{
if (check(0,5,i,y[i][j]))
addedge(s,i*4+j,dis(0,5,x[i],y[i][j]));
if (check(i,y[i][j],n+1,5))
addedge(i*4+j,t,dis(10,5,x[i],y[i][j]));
}
for (int i=1;i<=n;i++)
for (int j=i+1;j<=n;j++)
for (int k1=1;k1<=4;k1++)
for (int k2=1;k2<=4;k2++)
if (check(i,y[i][k1],j,y[j][k2]))
addedge(i*4+k1,j*4+k2,dis(x[i],y[i][k1],x[j],y[j][k2]));
queue<int>que;
que.push(s);
for (int i=s;i<=t;i++)
dist[i]=1000000;
dist[s]=0;
vis[s]=true;
while (!que.empty())
{
int x=que.front();
que.pop();
vis[x]=false;
for (int r=frst[x];r!=-1;r=nxt[r])
{
int y=ed[r];
if (dist[x]+val[r]<dist[y])
{
dist[y]=dist[x]+val[r];
if (!vis[y])
{
vis[y]=true;
que.push(y);
}
}
}
}
printf("%.2lf\n",dist[t]);
}
}
本文介绍了一个寻找二维房间中最短路径的问题,房间内含有多个带有两个门的障碍墙。通过建立图模型并使用最短路径算法求解,文章详细阐述了解决方案的实现细节。
1005

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



