基础算法题——城市间最短路程(Floyd算法)

Floyd算法

通过一个图的权值矩阵求出它的每两点间的最短路径矩阵。
其状态转移方程如下:map[i,j]:=min{map[i,k]+map[k,j],map[i,j]}

问题描述

现已知有N(N<=10)个城市M(M<=30)条路,保证每个城市之间有路,单向到达,每个城市之间的路程不一样,求任意两个城市之间最短路程。
样例输入
4 8 (N M)
1 2 2 (城市名称 城市名称 路程)
1 3 6
1 4 4
2 3 3
3 1 7
3 4 1
4 1 5
4 3 12

样例输出
0 2 5 4 (第一个城市到其他城市的最短路程)
9 0 3 4 (第二个城市到其他城市的最短路程)
6 8 0 1 …
5 7 10 0
题目来自 剑断青丝i

题目分析

在已知输入输出中我们可以得到图中信息:
基础算法题——城市间最短路程(Floyd算法)_第1张图片

考虑方法

由于该题是城市到城市之间的路程可能是不同的。
所以我们需要考虑一个结构,能够存储两个城市的城市名及路程。这时我们可以考虑使用二维数组。
例如:
城市1到城市2的路程表示:a[1][2] = 2
城市1到城市3的路程表示:a[1][3] = 6
城市3到城市1的路程表示:a[3][1] = 7
二维数组很轻松地帮我们解决了数据存储的问题。

初始化

一开始,我们需要将a[x][x]这类自己城市到自己城市的路程设置为0,将其他路程统一先设置为一个较大的数,方便将来程序比较的时候被替代。

求最短路径核心代码

这段代码很短,但它完成了求最短路程的工作,所以很棒。

//求最短路径核心代码
	for(int k=1; k<=n; k++)
	for(int i=1; i<=n; i++)
	for(int j=1; j<=n; j++)
	if(a[i][j]>a[i][k]+a[k][j])
	a[i][j]=a[i][k]+a[k][j];

k是比较因子,将完成当前最短路程与其他路程的比较工作。
一开始我很疑惑,为什么k的循环要放在最外一层而不是最里面那一层?于是我列举了循环部分过程,简化后得到下图。
基础算法题——城市间最短路程(Floyd算法)_第2张图片
我发现在k=1的时候,当前城市a到城市b的最短路程与城市a经过城市1后再到达城市b的路程作对比。若当前城市a到城市b的最短路程大于城市a经过城市1后再到达城市b的路程,则城市a经过城市1后再到达城市b的路程成为了当前城市a到城市b的最短路程。
接着就是k=2,k=3、k=4的情况,最后我们通过把将所有可能经过的城市都比较了一遍,得到城市与城市之间的最短路程。

	for(int i=1; i<=n; i++)
	for(int j=1; j<=n; j++)
	for(int k=1; k<=n; k++)
	if(a[i][j]>a[i][k]+a[k][j])
	a[i][j]=a[i][k]+a[k][j];

为了让大家更理解我讲的意思,我又画了幅讲解图。
基础算法题——城市间最短路程(Floyd算法)_第3张图片
我发现如果一开始k=e,当前城市a到城市d的最短路程为10。
但当我们知道城市d到城市c的路程为1,城市c到城市b的路程为1,城市b到城市a的路程为1后。
我们可以将k=c,得到城市d到城市b路程为2。当k=b时,得到城市d到城市a路程为3,最后城市d到城市a最短路程路程为3。
如果我们将k放在最里面那层循环的话,我们会发现有一些路程并不是最短的,因为每个城市到不同的城市只有一次更改最短路程的机会,如果后面的最短路程还不是最短,但是前面求最短路程的时候拿了不是最短路程去比较,那岂不是肯定会得到比最短路程长的路程吗?在讲解图里城市a到城市d的最短路程为只能是10, 只所以我们应当把k循环放在最外层。

最后附上代码:

#include
using namespace std;
int main()
{
     
	int i, n, j, k, a1, b1, c1, m;
	int inf=999999; 
	cin>>n>>m;
	int a[15][15];
	
	//初始化
	for(int i=1; i<=n; i++)//从城市i到城市j 
	{
     
		for(int j=1; j<=n; j++)
		{
     
			if(i==j)
			a[i][j]=0;//若为同一个城市则路程为0 
			else
			a[i][j]=inf;//若不同则置为最大路程 
		}
	}
	
	//输入已知路径
	for(int i=0; i<m; i++)
	{
     
		cin>>a1>>b1>>c1;
		a[a1][b1]=c1;
	}
	
	for(int i=1; i<5; i++)
	{
     
		for(int j=1; j<5; j++)
		printf("  a[%d][%d]:%7d",i, j, a[i][j]);
		cout<<endl;
	}
	cout<<endl;
	//将k作为转换因子放在最上面目的:
	//确保把将所有可能经过的城市都比较了一遍
	for(int k=1; k<=n; k++)
	for(int i=1; i<=n; i++)
	for(int j=1; j<=n; j++)
	if(a[i][j]>a[i][k]+a[k][j])
	a[i][j]=a[i][k]+a[k][j];
	//若从i到j的距离比从i到k再到j的距离大
	//就把原来的距离进行更新 
/*	for(int i=1; i<5; i++)  //验证代码
	{
		for(int j=1; j<5; j++)
		printf("  a[%d][%d]:%7d",i, j, a[i][j]);
		cout<
	
	for(int i=1; i<=n; i++)
	{
     
		for(int j=1; j<=n; j++)
		cout<<a[i][j]<<" ";
		cout<<endl;
	}
	return 0;
}

基础算法题——城市间最短路程(Floyd算法)_第4张图片

你可能感兴趣的:(基础算法题,算法)