关于求图的顶点间最短路径问题,基本分为两种算法:

  1. Dijkstra算法
  2. Floyd算法

Dijkstra算法是用来求图中某个源点到其他顶点的最短路径的,而Floyd是用来求图中任意两个顶点间的最短路径。原理上Floyd可以对Dijkstra算法遍历以便所有顶点得到,但是Flody的写法更简单一点。
下面以一道经典例题为例
题目来源:PTA
旅游规划
有了一张自驾旅游路线图,你会知道城市间的高速公路长度、以及该公路要收取的过路费。现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径。如果有若干条路径都是最短的,那么需要输出最便宜的一条路径。

输入格式:
输入说明:输入数据的第1行给出4个正整数N、M、S、D,其中N(2≤N≤500)是城市的个数,顺便假设城市的编号为0~(N−1);M是高速公路的条数;S是出发地的城市编号;D是目的地的城市编号。随后的M行中,每行给出一条高速公路的信息,分别是:城市1、城市2、高速公路长度、收费额,中间用空格分开,数字均为整数且不超过500。输入保证解的存在。

输出格式:
在一行里输出路径的长度和收费总额,数字间以空格分隔,输出结尾不能有多余空格。

输入样例:

4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20

输出样例:

3 40

附上利用Dijkstra算法的代码(分析可见代码注释)(AC源码)

#include <iostream>
#include <cstring>
using namespace std;

const int N = 510;
int dist[N][N];//两个城市间的距离 
int fee[N][N];	//城市间高速收费 
bool st[N];		//存储某个城市的最短路是否已经遍历过 
int n,m,s,d;	//n为城市数,m为路径数,s为起点,d为终点

void Dijstra(int s,int b)		//s为起点城市,b为终点城市 
{
	
	dist[s][s] = 0;				//初始化 
	
	for(int i = 0; i < n; i ++)//一共遍历n次
	{
		int t = -1;
		for(int j = 0; j < n; j ++)
		{
			if(!st[j] && (t == -1 || dist[s][t] > dist[s][j]))
			{
				t = j;//调用一个没有调用过的中间顶点
			}
		}
		
		st[t] = true;//某点被用过则标记以下
		
		for(int j = 0; j < n; j ++)//遍历所有点
		{
			if(dist[s][j] > dist[s][t] + dist[t][j]) //源点s通过t到达j 比 s直接到j 更短
			{
				dist[s][j] = dist[s][t] + dist[t][j]; //更新s到j的最短路径
				fee[s][j] = fee[s][t] + fee[t][j]; //更新收费额
			}
			else if(dist[s][j] == dist[s][t] + dist[t][j])
				fee[s][j] = min(fee[s][j], fee[s][t] + fee[t][j]);//路径相等时取收费最小的
			else continue;
		} 
	}
	
	cout << dist[s][b] << ' ' << fee[s][b];
	
}

int main()
{
	cin >> n >> m >> s >> d;
	
	memset(dist, 0x3f, sizeof dist);//初始化dist数组为inf 
	
	for(int i = 0; i < m; i ++)
	{
		int a,b,len,fe;
		cin >> a >> b >> len >> fe;
		if(dist[a][b] > len) //若两个城市间不止一条路径 
		{
            dist[a][b] = dist[b][a] = len;//无向图~~
            fee[a][b] = fee[b][a] =fe; 
        }
        else if(dist[a][b] == len) fee[a][b] = fee[b][a] = min(fee[a][b], fe);//路径相同时,收费取最小的 
	}
	
	Dijstra(s,d);
	
	return 0;
}

将Dijkstra算法换成Floyd算法也能AC

void Floyd(int s,int b)		//s为起点城市,b为终点城市 
{

	for(int t = 0; t < n; t ++)//t为path路径上的点
    {
        for(int i = 0; i < n; i ++)//i为起点
        {
		    for(int j = 0; j < n; j ++)//j为终点
		    {
			    if(i != j &&dist[i][j] > dist[i][t] + dist[t][j])//i通过t到达j 比 i直接到j 更短
			    {
				    dist[i][j] = dist[j][i] = dist[i][t] + dist[t][j];//由于是无向图,两个方向都要更新
				    fee[i][j] = fee[j][i] = fee[i][t] + fee[t][j];
			    }
			    else if(dist[i][j] == dist[i][t] + dist[t][j])
                    fee[i][j] = min(fee[i][j], fee[i][t] + fee[t][j]);//路径相同取收费最小
			    else continue;
		    } 
	    }
    }
	
	cout << dist[s][b] << ' ' << fee[s][b];
}

再单拎出Dijkstra算法

void Dijstra(int s,int b)		//s为起点城市,b为终点城市 
{
	
	dist[s][s] = 0;				//初始化 
	
	for(int i = 0; i < n; i ++)//一共遍历n次
	{
		int t = -1;
		for(int j = 0; j < n; j ++)
		{
			if(!st[j] && (t == -1 || dist[s][t] > dist[s][j]))
			{
				t = j;//调用一个没有调用过的中间顶点
			}
		}
		
		st[t] = true;//某点被用过则标记以下
		
		for(int j = 0; j < n; j ++)//遍历所有点
		{
			if(dist[s][j] > dist[s][t] + dist[t][j]) //源点s通过t到达j 比 s直接到j 更短
			{
				dist[s][j] = dist[s][t] + dist[t][j]; //更新s到j的最短路径
				fee[s][j] = fee[s][t] + fee[t][j]; //更新收费额
			}
			else if(dist[s][j] == dist[s][t] + dist[t][j])
				fee[s][j] = min(fee[s][j], fee[s][t] + fee[t][j]);//路径相等时取收费最小的
			else continue;
		} 
	}
	
	cout << dist[s][b] << ' ' << fee[s][b];
	
}

可以作一个对比观察。
如果还要求路径经过的城市,可以多增加一个path邻接矩阵来存储。
另外,这两个算法可以作为一个代码模板,类似的题基本可以一个模板过。