一、最短路径
- 最短路径问题是图论研究中的一个经典算法问题, 旨在寻找图(由结点和路径组成的)中两结点之间的最短路径。
- 算法具体的形式包括:
- 确定起点的最短路径问题 - 即已知起始结点,求最短路径的问题。
- 确定终点的最短路径问题 - 与确定起点的问题相反,该问题是已知终结结点,求最短路径的问题。在无向图中该问题与确定起点的问题完全等同,在有向图中该问题等同于把所有路径方向反转的确定起点的问题。
- 确定起点终点的最短路径问题 - 即已知起点和终点,求两结点之间的最短路径。
- 全局最短路径问题 - 求图中所有的最短路径。
二、Floyd算法(弗洛伊德算法)
算法步骤
将vi到vj的最短路径长度初始化,即D[i][j]=G.arcs[i][j],然后进行n次比较和更新。
- 在vi和vj间加入顶点v1,比较(vi, vj)和(vi, v1, vj)的路径长度,取其中较短者作为vi到vj的中间顶点序号不大于0的最短路径。
- 在vi和vj间加入顶点v1,得到(vi, … , v1) 和(v1, … ,vj),其中(vi, … , v1) 是v1到vj的且中间顶点的序号不大于0的最短路径,(v1,··,v)是v到v的且中间顶点的序号不大于0的最短路径,这两条路径已在上一步中求出。比较(vi, … , v1, … , vj)与上一步求出的vi到vj的中间顶点序号不大于0的最短路径,取其中较短者作为vi到vj的中间顶点序号不大于1的最短路径。
- 依次类推,在vi和vj间加入顶点v1,若(vi, … , vk)和(vk, … ,vj)分别是从vi到vk以和从vk到vj的中间顶点的序号不大于k-1的最短路径,则将(vi, … , vk , ··· , vj)和已经得到的从vi到vj且中间顶点序号不大于k-1的最短路径相比较,其长度较短者便是从vi到vj的中间顶点的序号不大于k的最短路径。这样,经过n次比较后,最后求得的必是从vi到vj的最短路径。
- 按此方法,可以同时求得各对顶点间的最短路径。
三、举一个栗子(1076 : Floyd-Warshall)
Description
暑假,小哼准备去一些城市旅游。有些城市之间有公路,有些城市之间则没有,如下图。为了节省经费以及方便计划旅程,小哼希望在出发之前知道任意两个城市之前的最短路程。
Input
- 第一行四个数为n,m,n表示顶点个数,m表示边的条数。
- 接下来m行,每一行有三个数t1、t2 和t3,表示顶点t1到顶点t2的路程是t3。请注意这些t1->t2是单向的。
Output
输出一个n*n的矩阵,第n行第n列表示定点n到n的距离。每一行两个数间由空格隔开
Sample Input
5 8
1 2 2
2 3 3
3 4 4
4 5 5
5 3 3
3 1 4
2 5 7
1 5 10
Sample Output
0 2 5 9 9
7 0 3 7 7
4 6 0 4 9
12 14 8 0 5
7 9 3 7 0
code
详见注释
#include <iostream>
#define Max 503
#define INF 0xcffff
using namespace std;
typedef struct AMGraph { //定义邻接矩阵
int vex, arc;
int arcs[Max][Max];
};
int dis[Max][Max], path[Max][Max]; //dis存最短路程,path保存路径
void Floyd(AMGraph &G) //弗洛伊德算法
{
for (int i = 1; i <= G.vex; i++) //初始化dis和path
for (int j = 1; j <= G.vex; j++)
{
dis[i][j] = G.arcs[i][j];
if (dis[i][j] != INF&&i != j) path[i][j] = i;
else path[i][j] = -1;
}
/***************Floyd核心算法****************/
for(int k=1; k<=G.vex; k++) //遍历每个点
for(int i=1; i<=G.vex; i++) //遍历每条边
for (int j = 1; j <= G.vex; j++)
{
if (dis[i][k] + dis[k][j] < dis[i][j]) {
dis[i][j] = dis[i][k] + dis[k][j]; //松弛操作
path[i][j] = k; //保存j前驱结点k
}
}
}
void find(int x, int y) //输出路径
{
if (path[x][y] == x) return ; //如果x,y之间无节点,则结束查找
int t = path[x][y]; //如果x,y之间具有节点t,则查找t, y
cout << "->" << t;
find(t, y);
return;
}
void putin(AMGraph &G) //输入图
{
int u, v, w;
cin >> G.vex >> G.arc;
for (int i = 1; i <= G.vex; i++) //初始化邻接矩阵
for (int j = 1; j <= G.vex; j++)
{
if (i == j) G.arcs[i][j] = 0;
else G.arcs[i][j] = INF;
}
for (int i = 0; i < G.arc; i++)
{
cin >> u >> v >> w;
G.arcs[u][v] = w;
// G.arcs[v][u] = w;
}
}
void putout(AMGraph &G) //输出最短路矩阵、起点v1到各点的最短距离和路径
{
//cout << "最短路矩阵为:\n";
for (int i = 1; i <= G.vex; i++)
{
for (int j = 1; j < G.vex; j++)
cout << path[i][j] << " ";
cout << path[i][G.vex] << endl;
}
for (int i = 2; i <= G.vex; i++)
{
cout << "从初始点 v1 到 v" << i << "的最短路径路程为:" << dis[1][i] << endl;
cout << "路径为: 1";
find(1, i);
cout << "->" << i << endl;
}
}
int main()
{
AMGraph G;
putin(G);
Floyd(G);
putout(G);
return 0;
}
运行截图
去注释打印路径结果
蒟蒻一只,欢迎指正