图论算法----最短路径Floyed算法和Dijkstra算法详解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/C20180602_csq/article/details/52850104

一、题目描述

最短路径问题(floyed.cpp & dijkstra.cpp)

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

输入
第1行:1个整数n
第2..n+1行:每行2个整数x和y,描述了一个点的坐标
第n+2行:1个整数m,表示图中连线的数量
接下来有m行,每行2个整数i和j,表示第i个点和第j个点之间有连线
最后1行:2个整数s和t,分别表示源点和目标点

输出
第1行:1个浮点数,表示从s到t的最短路径长度,保留2位小数

样例输入
5
0 0
2 0
2 2
0 2
3 1
5
1 2
1 3
1 4
2 5
3 5
1 5

样例输出
3.41


二、分析

1、Floyed算法O(n³)
我们先对输入的数据进行初始化:
<span style="font-size:18px;">#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
double dis[105][105];//dis[i][j]表示点i到点j的最短路径长度
int zb[105][2];//坐标
int main()
{
	//freopen("floyed.in","r",stdin);
	//freopen("floyed.out","w",stdout);
	int n,m,i,j,k,x,y,q,z;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
		scanf("%d%d",&zb[i][0],&zb[i][1]);
	scanf("%d",&m);
	memset(dis,0x7f,sizeof(dis));//清为最大值,以便后面求最短路
	for(i=1;i<=m;i++){
		scanf("%d%d",&x,&y);
		dis[x][y]=sqrt(pow(1.0*(zb[x][0]-zb[y][0]),2)+pow(1.0*(zb[x][1]-zb[y][1]),2));//计算两点之间的距离
		dis[y][x]=dis[x][y];
	}
	scanf("%d%d",&q,&z);
}</span>
floyed算法其实就是3个for循环,用i、j、k三个循环变量来枚举每一个点。用k来枚举中转点,i、j来枚举i到j的点。

如果dis[i][k]+dis[k][j]<dis[i][j],则dis[i][j]=dis[i][k]+dis[k][j]。就是 i 到 k 的距离与 k 到 j 的距离的和,小于 i 到 j 的距离,就把dis[i][j]变成 i 到 k 的距离与 k 到 j 的距离
和。
<span style="font-size:18px;">for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(i!=j&&j!=k&&i!=k)
dis[i][j]=min(dis[i][k]+dis[k][j],dis[i][j]);</span>
最后输出结果:
<span style="font-size:18px;">printf("%.2f",dis[q][z]);</span>

2、Dijkstra算法O(n²)

还是先进行初始化:
<span style="font-size:18px;">#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
double f[105][105];//用f[x][y]来存x,y的距离(但不是最短距离)
double dis[105];//存最终结果
bool b[105];//判断重复
int zb[105][2];
int main()
{
	//freopen("dijkstra.in","r",stdin);
	//freopen("dijkstra.out","w",stdout);
	int n,m,i,j,k,x,y,q,z,xi;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
		scanf("%d%d",&zb[i][0],&zb[i][1]);
	scanf("%d",&m);
	memset(f,0x7f,sizeof(f));
	for(i=1;i<=m;i++){
		scanf("%d%d",&x,&y);
		f[x][y]=sqrt(pow(1.0*(zb[x][0]-zb[y][0]),2)+pow(1.0*(zb[x][1]-zb[y][1]),2));
		f[y][x]=f[x][y];
	}
	scanf("%d%d",&q,&z);
}</span>
我们可以发现dis变成了一维数组,因为Dijkstra算法是一种用来计算一个点到其他所有点的最短路径算法,
Dijkstra算法是先用一个循环变量 i 来枚举所有点,把每一个枚举过的点在b数组中标记为1,然后记录下距离
点 i 最近的一个点 k ,以点 k 来进行其他最短距离的更新,
<span style="font-size:18px;">for(i=1;i<=n;i++)
		dis[i]=f[q][i];
	b[q]=1;
	dis[q]=0;
	for(i=1;i<=n-1;i++){
		xi=10000000;
		k=0;
		for(j=1;j<=n;j++){
			if(b[j]==0&&dis[j]<xi){
				xi=dis[j];
				k=j;
			}
		}
		if(k==0)
			break;
		b[k]=1;
		for(j=1;j<=n;j++)//进行更新
			dis[j]=min(dis[j],dis[k]+f[k][j]);
	}
	printf("%.2f",dis[z]);</span>





展开阅读全文

没有更多推荐了,返回首页