1. 程式人生 > >POJ 1556 The Doors(簡單計算幾何+最短路)

POJ 1556 The Doors(簡單計算幾何+最短路)

smart order tom amp fabs 題目 -- opera 兩個

●贅述題目

10*10的房間內,有豎著的一些墻(不超過18個)。問從點(0,5)到(10,5)的最短路。

按照輸入樣例,輸入的連續5個數,x,y1,y2,y3,y4,表示(x,0--y1),(x,y2--y3),(x,y4--10)是墻壁。

●題解

方法:建圖(用到簡單計算幾何)+最短路

○記錄下每個端點。

○包含起點,終點,以及每個墻的可以走的端點,如下圖:

○然後枚舉點,嘗試兩兩組合連(線段)邊,若該線不會在墻上,即不會與墻壁線段相交,就add_adge()。

效果圖如下:

技術分享

如何判斷呢? 計算幾何唄。我用的方法如下,須同時滿足兩個條件:

技術分享

●代碼

#include<cmath>
#include<cstdio>
#include<queue>
#include<cstring>
#include<iostream>
using namespace std;
const double eps=1e-8;
typedef pair<double,int> pii;
struct point{double x,y;}p[105];
struct seg{double x1,y1,x2,y2;}w[105];
struct vec{
	double x,y;
	double operator ^(const vec rtm) {return x*rtm.y-y*rtm.x;} //向量叉乘(模) 
	vec operator -(const vec rtm) {return (vec){x-rtm.x,y-rtm.y};}
}v1,v2,v3,v4,v5,v6,v7,v8;
struct edge{
	int to; double co; int next;
}e[10005];
int head[105];
double d[105];
int n,dnt,snt,ent; 
double dis(point a,point b) {return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}
int sign(double a)
{
	if(fabs(a)<eps) return 0;
	return a>0?1:-1;
}
void add(int u,int v,double c)
{
	e[ent]=(edge){v,c,head[u]};head[u]=ent++;
	e[ent]=(edge){u,c,head[v]};head[v]=ent++;
}
void dijkstra()
{
	for(int i=1;i<=dnt;i++) d[i]=1e7+9;
	priority_queue<pii> q;
	q.push((pii){0,1});d[1]=0;
	while(!q.empty())
	{
		pii u=q.top();q.pop();
		if(d[u.second]<u.first) continue;
		for(int i=head[u.second];i!=-1;i=e[i].next)
		{
			int v=e[i].to;
			if(d[v]>d[u.second]+e[i].co)
			{
				d[v]=d[u.second]+e[i].co;
				q.push((pii){d[v],v});
			}
		}
	}
}
int main()
{
	p[++dnt]=(point){0,5}; p[++dnt]=(point){10,5};
	while(1)
	{
		memset(head,-1,sizeof(head));
		dnt=2;snt=0;ent=0;
		scanf("%d",&n);
		if(n==-1) break;
		double x,y1,y2,y3,y4;
		for(int i=1;i<=n;i++)
		{
			scanf("%f%f%f%f%f",&x,&y1,&y2,&y3,&y4);
			p[++dnt]=(point){x,y1}; p[++dnt]=(point){x,y2}; p[++dnt]=(point){x,y3}; p[++dnt]=(point){x,y4};
			w[++snt]=(seg){x,0,x,y1}; w[++snt]=(seg){x,y2,x,y3}; w[++snt]=(seg){x,y4,x,10};
		} 
		bool fg;
		for(int i=1;i<dnt;i++) for(int j=i+1;j<=dnt;j++)
		{		
			fg=1;	
			for(int k=1;k<=snt;k++)
			{
				v1=(vec){p[i].x-w[k].x1,p[i].y-w[k].y1};
				v2=(vec){p[i].x-w[k].x2,p[i].y-w[k].y2};
				v3=(vec){p[j].x-w[k].x1,p[j].y-w[k].y1};
				v4=(vec){p[j].x-w[k].x2,p[j].y-w[k].y2};	
				
				v5=(vec){0,0}-v1;
				v6=(vec){0,0}-v3;
				v7=(vec){0,0}-v2;
				v8=(vec){0,0}-v4;
				if(sign((v1^v2)*(v3^v4))<0&&(sign(v5^v6)*(v7^v8))<0) {fg=0;break;}
			}	
			if(fg) add(i,j,dis(p[i],p[j]));
		}
		dijkstra();
		printf("%.2f\n",d[2]);
	}	
	return 0;
}

POJ 1556 The Doors(簡單計算幾何+最短路)