NYOJ有趣的问题(单源最短路径dijkstra)

思路:这题的难度主要是在建图上,建完图之后就是求单源最短路径问题。可用dijkstra算法.要注意他给出的墙的x坐标不是有序 的。

#include<stdio.h>
#include<math.h>
#include<string.h>
#define MAX 999
struct Position
{
	double x;
	double y;
}p[100]; 
double map[100][100],pos[20][5],dis[100];
int used[100],k;
bool solve(Position p1,Position p2,int bian)
{

	if(p1.x==p2.x)          //如果是一面墙上的点则不考虑 
	  return false;
	  double left=p1.x<p2.x?p1.x:p2.x;     
	  double right=p1.x>p2.x?p1.x:p2.x;
	if(pos[bian][0]<=left||pos[bian][0]>=right)   // 如果该墙不在这两点连线的范围之内则也不考虑 
	 return true;
	double a,b,posY;
	a=(p1.y-p2.y)/(p1.x-p2.x);
	b=p1.y-p1.x*a;
	posY=a*pos[bian][0]+b;
	if(posY>=pos[bian][1]&&posY<=pos[bian][2]||posY>=pos[bian][3]&&posY<=pos[bian][4])  
 		return true;
	return false;
}
double dist(Position p1,Position p2)
{
	double res=sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
	return res;
}
double djks(int s)
{
	memset(used,0,sizeof(used));
	double min;
	int i,j,u;
	for(i=0;i<=k;i++)
	 	dis[i]=map[s][i];
	dis[i]=0;
	for(i=1;i<=k;i++)
	{
		min=MAX;
		for(j=1;j<=k;j++)
		{
			if(used[j]!=1&&dis[j]<min)
			{
				min=dis[j];
				u=j;
			}
		}
		used[u]=1;
		for(j=0;j<=k;j++)
		{
			if(used[j]!=1&&dis[u]+map[u][j]<dis[j])
			{
				dis[j]=dis[u]+map[u][j];
			}
		}
	}
	return dis[k];
}
int main()
{
	int n,i,j,g;
	double a,b;
	while(scanf("%d",&n)&&n!=-1)
	{
		k=0;
		p[k].x=0;
		p[k++].y=5;
		for(i=1;i<=n;i++)
		{
			scanf("%lf%lf%lf%lf%lf",&pos[i][0],&pos[i][1],&pos[i][2],&pos[i][3],&pos[i][4]);  //将墙上的端点转化为点 
			p[k].x=pos[i][0];
			p[k++].y=pos[i][1];
			p[k].x=pos[i][0];
			p[k++].y=pos[i][2];
			p[k].x=pos[i][0];
			p[k++].y=pos[i][3];
			p[k].x=pos[i][0];
			p[k++].y=pos[i][4];
		}
		p[k].x=10;
		p[k].y=5;
		for(i=0;i<=k;i++)
		{
			for(j=0;j<=k;j++)
			{
				map[i][j]=MAX;
			}
		}
		for(i=0;i<=k;i++)
			for(j=0;j<=k;j++)
			{
				for(g=1;g<=n;g++)       //判断两点之间是否可以直接连通 
				{
					if(!solve(p[i],p[j],g))     
					break;
				}
				if(g==n+1)
				{
					double d=dist(p[i],p[j]);  //求两点距离 
					map[i][j]=d;
				}
			}
		double res=djks(0);
		printf("%.2lf\n",res);
	}
	return 0;
}
/*
1
5 4 6 7 8
2
4 2 7 8 9
7 3 4.5 6 7
-1
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值