题目链接:http://poj.org/problem?id=1556
Time Limit: 1000MS Memory Limit: 10000K
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.
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
题意:
给出一个(0,0)(0,10)(10,0)(10,10)的正方形房子,里面有一些墙,每堵墙上有两扇门;
求从(0,5)到(10,5)的最短距离;
题解:
是一道不错的题目,一定程度上结合了计算几何和最短路;
建一个有向图,把(0,5)作为起始点,(10,5)作为目标点,其他所有墙上的门的两个端点也加入到这个有向图中;
尝试枚举连接任意两个点,只有当这两个点之间没有墙阻隔,这连个点才可能连接起来;
所有能连接起来的两个点都作为一条有向边加入到有向图中,并且靠左的作为u,靠右的作为v,而两点之间的距离作为w;
最后,我们只要求出起始点和目标点之间的最短路即可。
AC代码:
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<algorithm> #include<queue> #define MAXN 4*20 #define INF 0x3f3f3f3f using namespace std; //--------------------------------------计算几何模板 - st-------------------------------------- const double eps = 1e-6; struct Point{ double x,y; Point(double tx=0,double ty=0):x(tx),y(ty){} }; typedef Point Vctor; //向量的加减乘除 Vctor operator + (Vctor A,Vctor B){return Vctor(A.x+B.x,A.y+B.y);} Vctor operator - (Point A,Point B){return Vctor(A.x-B.x,A.y-B.y);} Vctor operator * (Vctor A,double p){return Vctor(A.x*p,A.y*p);} Vctor operator / (Vctor A,double p){return Vctor(A.x/p,A.y/p);} int dcmp(double x) { if(fabs(x)<eps) return 0; else return (x<0)?(-1):(1); } bool operator == (Point A,Point B){return dcmp(A.x-B.x)==0 && dcmp(A.y-B.y)==0;} //向量的点积,长度,夹角 double Dot(Vctor A,Vctor B){return A.x*B.x+A.y*B.y;} double Length(Vctor A){return sqrt(Dot(A,A));} double Angle(Vctor A,Vctor B){return acos(Dot(A,B)/Length(A)/Length(B));} //叉积,三角形面积 double Cross(Vctor A,Vctor B){return A.x*B.y-A.y*B.x;} double TriangleArea(Point A,Point B,Point C){return Cross(B-A,C-A);} //判断线段是否规范相交 bool SegmentProperIntersection(Point a1,Point a2,Point b1,Point b2) { double c1 = Cross(a2 - a1,b1 - a1), c2 = Cross(a2 - a1,b2 - a1), c3 = Cross(b2 - b1,a1 - b1), c4 = Cross(b2 - b1,a2 - b1); return dcmp(c1)*dcmp(c2)<0 && dcmp(c3)*dcmp(c4)<0; } //--------------------------------------计算几何模板 - ed-------------------------------------- //--------------------------------------spfa算法 - st-------------------------------------- double d[MAXN]; double mp[MAXN][MAXN]; bool vis[MAXN]; void init(int n){for(int i=0;i<n;i++) for(int j=0;j<n;j++) mp[i][j]=0;} void addedge(int u,int v,double w){mp[u][v]=w;} void spfa(int st,int n) { for(int i=0;i<n;i++) { i==st ? d[i]=0 : d[i]=INF; vis[i]=0; } queue<int> q; q.push(st); vis[st]=1; while(!q.empty()) { int u=q.front();q.pop();vis[u]=0; for(int v=0;v<n;v++) { if(u==v || mp[u][v]==0) continue; double tmp=d[v]; if(d[v]>d[u]+mp[u][v]) d[v]=d[u]+mp[u][v]; if(d[v]<tmp && !vis[v]) { q.push(v); vis[v]=1; } } } } //--------------------------------------spfa算法 - ed-------------------------------------- int n; vector<Point> p; int main() { while(scanf("%d",&n) && n!=-1) { p.clear(); p.push_back(Point(0,5)); for(int i=1;i<=n;i++) { double x,y1,y2,y3,y4; scanf("%lf%lf%lf%lf%lf",&x,&y1,&y2,&y3,&y4); p.push_back(Point(x,y1)); p.push_back(Point(x,y2)); p.push_back(Point(x,y3)); p.push_back(Point(x,y4)); } p.push_back(Point(10,5)); int _size=p.size(); init(_size); for(int i=0;i<_size;i++) { for(int j=i+1;j<_size;j++) { if(p[i].x==p[j].x) continue; bool ok=1; for(int k=i+1;k<j;k++) { if(k%4==1) { if(SegmentProperIntersection(p[i],p[j],p[k],Point(p[k].x,0))) { ok=0; break; } } else if(k%4==2) { if(SegmentProperIntersection(p[i],p[j],p[k],p[k+1])) { ok=0; break; } } else if(k%4==3) { if(SegmentProperIntersection(p[i],p[j],p[k],p[k-1])) { ok=0; break; } } else if(k%4==0) { if(SegmentProperIntersection(p[i],p[j],p[k],Point(p[k].x,10))) { ok=0; break; } } } if(ok) addedge(i,j,Length(p[i]-p[j])); } } spfa(0,_size); printf("%.2f ",d[_size-1]); } }