1. 程式人生 > >POJ_1556_The Doors_判斷線段相交+最短路

POJ_1556_The Doors_判斷線段相交+最短路

ont printf OS for eas mic light 最短路徑 eof

POJ_1556_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


你要通過一個包含阻礙墻的房間來找到最短路徑的長度。
在x=0,x=10,y=0,y=10時,總會有邊。路徑的初始和終點總是(0,5)和(10,5),也會有從0到18的垂直墻,每一個都有兩道門。
輸出應該包含每個房間的一行輸出。這一行應該包含小數點後兩位小數的最小路徑長度,並且總是顯示小數點後兩位小數。這條線不應該有空格。



把所有點拿出來連邊建圖,判斷一下中間是否有擋住的墻壁即可。
這裏的線段判斷相交用的方法很菜:判斷兩直線交點在不在線段上。
因為有除法誤差可能比較大。

代碼:
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <math.h>
using namespace std;
typedef double f2;
#define N 10050
#define eps 1e-6
int head[N],to[N],nxt[N],cnt,n,vis[N],tot,S,T,ghj;
f2 val[N],dis[N];
priority_queue<pair<f2,int> >q;
//********************************************
struct Point {
	f2 x,y;
	Point() {}
	Point(f2 x_,f2 y_) :
		x(x_),y(y_) {}
	Point operator + (const Point &p) const {return Point(x+p.x,y+p.y);}
	Point operator - (const Point &p) const {return Point(x-p.x,y-p.y);}
	Point operator * (f2 rate) const {return Point(x*rate,y*rate);}
};
f2 dot(const Point &p1,const Point &p2) {return p1.x*p2.x+p1.y*p2.y;}
f2 cross(const Point &p1,const Point &p2) {return p1.x*p2.y-p1.y*p2.x;}
Point a[N];
typedef Point Vector;
struct Line {
	Point p;Vector v;
	Line() {}
	Line(const Point &p_,const Vector &v_) :
		p(p_),v(v_) {}
};
Line b[N];
Point get_point(const Line &l1,const Line &l2) {
	Vector u=l1.p-l2.p;
	f2 t=cross(l2.v,u)/cross(l1.v,l2.v);
	return l1.p+l1.v*t;
}
bool judge(const Point &p1,const Point &p2,const Line &l) {
	if(l.p.x<p1.x+eps||l.p.x>p2.x-eps) return 0;
	Line l1=Line(p1,p2-p1),l2=Line(l.p,l.v-l.p);
	Point p3=get_point(l1,l2);
	return p3.x>p1.x&&p3.x<p2.x&&p3.y>l.p.y&&p3.y<l.v.y;
}
//********************************************************
inline void add(int u,int v,f2 w) {
	to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; val[cnt]=w;
}
void dij() {
	memset(dis,0x7f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	dis[S]=0;q.push(make_pair(0,S));
	while(!q.empty()) {
		int x=q.top().second;q.pop();
		if(vis[x]) continue;
		vis[x]=1;
		int i;
		for(i=head[x];i;i=nxt[i]) {
			if(dis[to[i]]>dis[x]+val[i]) {
				dis[to[i]]=dis[x]+val[i];
				q.push(make_pair(-dis[to[i]],to[i]));
			}
		}
	}
	printf("%.2lf\n",dis[T]);
}
void init() {
	memset(head,0,sizeof(head)); cnt=0; tot=0; ghj=0;
}
int main() {
	while(scanf("%d",&n)&&n!=-1) {
		int i,j,k;
		init();
		f2 x,y,z,w,h;
		for(i=1;i<=n;i++) {
			scanf("%lf%lf%lf%lf%lf",&x,&y,&z,&w,&h);
			a[++tot]=Point(x,y);
			b[++ghj]=Line(Point(x,0),a[tot]);
			a[++tot]=Point(x,z);
			a[++tot]=Point(x,w);
			b[++ghj]=Line(a[tot-1],a[tot]);
			a[++tot]=Point(x,h);
			b[++ghj]=Line(a[tot],Point(x,10));
		}
		a[++tot]=Point(0,5); S=tot;
		a[++tot]=Point(10,5); T=tot;
		for(i=1;i<=tot;i++) {
			for(j=1;j<=tot;j++) {
				if(a[j].x>a[i].x+eps) {
					int flg=1;
					for(k=1;k<=ghj;k++) {
						if(judge(a[i],a[j],b[k])) {
							flg=0; break;
						}
					}
					if(flg) {
						add(i,j,sqrt((a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y)));
						//printf("%.2lf\n",sqrt((a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y)));
					}
				}
			}
		}
		dij();
	}
}

 

POJ_1556_The Doors_判斷線段相交+最短路