SSL·最短路径问题【FDBS】

Description–

  • 平面上有n个点(N<=100),每个点的坐标均在-10000~10000之间。
  • 其中的一些点之间有连线。若有连线,则表示可从一个点到达另一个点,即两点间有通路,通路的距离为两点直线的距离。
  • 现在的任务是找出从一点到另一点之间的最短路径。

Input–

输入文件 short.in,共有n+m+3行,其中:
第一行为一个整数n。
第2行到第n+1行(共n行),每行的两个整数x和y,描述一个点的坐标(以一个空格隔开)。
第n+2行为一个整数m,表示图中的连线个数。
此后的m行,每行描述一条连线,由两个整数I,j组成,表示第i个点和第j个点之间有连线。
最后一行:两个整数s和t,分别表示源点和目标点。

Output–

输出文件short.out仅一行,一个实数(保留两位小数),表示从S到T的最短路径的长度。


Sample Input–

5
0 0
2 0
2 2
0 2
3 1
5
1 2
1 3
1 4
2 5
3 5
1 5

Sample Output–

3.41


解题思路–

Floyed-Warshall(弗洛伊德)算法
Dijkstra算法
Bellman-Ford(福特)算法
SPFA算法
注意事项:

  • 勾股定理:
    a^2 + b^2 = c^2

代码–

方法一

Floyed(弗洛伊德)算法

#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
struct emm
{
	int x,y;
}a[110];
double b[110][110];
int l,ll,s,t,n,m;
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;++i)
	  scanf("%d%d",&a[i].x,&a[i].y);
	scanf("%d",&m);
	memset(b,0x7f,sizeof(b));
	for (int i=1;i<=m;++i)
	{
		scanf("%d%d",&l,&ll);
		b[l][ll]=b[ll][l]=sqrt(pow(double(a[l].x-a[ll].x),2)+pow(double(a[l].y-a[ll].y),2));//勾股定理
	}
	scanf("%d%d",&s,&t);//求从s到t的最短路径
	for (int k=1;k<=n;++k)//Floyed
	  for (int i=1;i<=n;++i)
	    for (int j=1;j<=n;++j)
	    	if (k!=i && k!=j && i!=j)
	    	  if (b[i][j]>b[i][k]+b[k][j])
	    	    b[i][j]=b[i][k]+b[k][j];
	printf("%.2lf\n",b[s][t]);

	return 0;
}
方法二

Dijkstra算法

#include<cstdio>
#include<iostream>
#include<cmath>
const double hhg=75000;
struct emm
{
	int x,y;
}a[101];
int n,m,s,t,o,l,ll;
bool f[101];
double b[101][101],c[101],yyg;
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;++i)
	  scanf("%d%d",&a[i].x,&a[i].y);
	for (int i=1;i<=n;++i)
	  for (int j=1;j<=n;++j)
	    b[i][j]=hhg;//手动初始化
	scanf("%d",&m);
	for (int i=1;i<=m;++i)
	{
		scanf("%d%d",&l,&ll);
		b[l][ll]=b[ll][l]=sqrt(pow(double(a[l].x-a[ll].x),2)+pow(double(a[l].y-a[ll].y),2));//勾股定理
	}
	scanf("%d%d",&s,&t);//求从s到t的最短路径
	for (int i=1;i<=n;++i) c[i]=b[s][i];//Dijkstra
	f[s]=true,c[s]=0;//标记f[s]为“已求出”;c[s]到自己的最短距离是0
	for (int i=1;i<n;++i)
	{
		yyg=hhg,o=0;//yyg放最大值;o清零;
		for (int j=1;j<=n;++j)
		  if (!f[j] && c[j]<yyg)
		  	yyg=c[j],o=j;//yyg存现阶段的最小值,o存最小值的位置
	    if (o==0) break;
	    f[o]=true;//标记
	    for (int j=1;j<=n;++j)
	      if (c[j]>c[o]+b[o][j] && !f[j])//判断是否可更新
	        c[j]=c[o]+b[o][j];//更新
	}
	printf("%.2lf\n",c[t]);
}
方法三

Bellman-Ford(福特)算法

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
struct emm
{
	int x,y;
}a[101];
double b[1001],c[101];
bool h[101];
int l[1001],ll[1001],n,m,s,t;
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;++i)
	  scanf("%d%d",&a[i].x,&a[i].y);
	scanf("%d",&m);
	for (int i=1;i<=m;++i)
	{
		scanf("%d%d",&l[i],&ll[i]);
		b[i]=sqrt(pow(double(a[l[i]].x-a[ll[i]].x),2)+pow(double(a[l[i]].y-a[ll[i]].y),2));//勾股定理
	}
	scanf("%d%d",&s,&t);//求从s到t的最短路径
	memset(c,0x7f,sizeof(c));//Ford
	c[s]=0;//c[s]到自己的最短距离是0
	for (int i=1;i<n;i++)
	{
		bool hfy=false;//判断更新是否结束
	    for (int j=1;j<=m;j++)
        {
            if (c[l[j]]+b[j]<c[ll[j]])//
		    {                         //
		  	    c[ll[j]]=c[l[j]]+b[j];//双向判断更新
		  	    hfy=true;             //
		    }                         //
            if (c[ll[j]]+b[j]<c[l[j]])//
		    {
		        c[l[j]]=c[ll[j]]+b[j];
		        hfy=true;
		    } 
        }
        if (!hfy) break;
	}
    printf("%.2lf",c[t]);
	
	return 0;
}
方法四

SPFA算法

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
struct emm
{
	int x,next;
	double y;
}f[2001];
double dis[101];
bool pd[101];
int a[101][2],ls[101],bty[2001];
int n,m,ll,lr,s,t,l,r=1,u,o,q;
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;++i)
	  scanf("%d%d",&a[i][0],&a[i][1]);
	scanf("%d",&m);
	for (int i=1;i<=m;++i)
	{
		scanf("%d%d",&ll,&lr);
		f[++t].x=lr; f[t].next=ls[ll]; ls[ll]=t;//邻接表
		f[t].y=sqrt(pow(double(a[ll][0]-a[lr][0]),2)+pow(double(a[ll][1]-a[lr][1]),2));//勾股定理
    	f[++t].x=ll; f[t].next=ls[lr]; ls[lr]=t;
    	f[t].y=f[t-1].y;
	}
	scanf("%d%d",&s,&q);
	memset(dis,0x7f,sizeof(dis));
	dis[s]=0,bty[1]=s,pd[s]=true;
	while (l<r)
	{
		l++,u=bty[l];//头指针向下移一位,取出指向的点l
		pd[u]=false;//把处理过的点退出标记
		for (int i=ls[u];i;i=f[i].next)
			if (dis[o=f[i].x]>dis[u]+f[i].y)//判断此点是否可更新(是↓)
            {
            	dis[o]=dis[u]+f[i].y;
            	if (!pd[o])//判断此点在不在队列里面(不在↓)
            	{
            		pd[o]=true;//标记此点在队列中
            		r++;
            		bty[r]=o;//加入队列
            	}
            }
	}
	printf("%.2lf",dis[q]);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值