C/C++ 最短路径-Dijkstra算法 (路径的保存和输出)

一、最短路径

  • 最短路径问题是图论研究中的一个经典算法问题, 旨在寻找图(由结点和路径组成的)中两结点之间的最短路径。
  • 算法具体的形式包括:
    • 确定起点的最短路径问题 - 即已知起始结点,求最短路径的问题。
    • 确定终点的最短路径问题 - 与确定起点的问题相反,该问题是已知终结结点,求最短路径的问题。在无向图中该问题与确定起点的问题完全等同,在有向图中该问题等同于把所有路径方向反转的确定起点的问题。
    • 确定起点终点的最短路径问题 - 即已知起点和终点,求两结点之间的最短路径。
    • 全局最短路径问题 - 求图中所有的最短路径。

二、Dijkstra算法(迪杰斯特拉算法)

算法步骤

初始化:

  • 将源点v0加到S中,即S[v0] = true;
  • 将v0到各个终点的最短路径长度初始化为权值,即D[i] = G.arcs[v0][vi] (vi ∈ V-S);
  • 如果v0和顶点vi之间有弧,则将vi的前驱置为v0,即Path[i] = v0,否则Path[i] = -1;

循环n-1次,执行以下操作:

  • 选择下一条最短路径的终点vk,使得:D[k] = Min{D[i] | vi ∈ V-S};
  • 将vk加到S中,即S[vk] = true;
  • 根据条件更新从 v0 出发到集合 V-S 上任一顶点的最短路径的长度,若条件 D[k] + G.arcs[k][i] < D[i] 成立,则更新 D[i] = D[k]+G.arcs[k][i], 同时更改 vi 的前驱为 vk; Path[i] = k;

三、举个栗子(1077 : Dirjkstra)

Description

给定n个点,m条有向边, 求每个点到1号点的最短距离

Input

  • 第一行两个数为n,m,n表示顶点个数,m表示边的条数。 (1 ≤ n, m ≤ 100 )
  • 接下来m行,每一行有三个数t1、t2 和t3,表示顶点 t1 到顶点 t2 的路程是 t3。请注意这些 t1 -> t2 是单向的。

Output

输出N个数,分别为每个点到1号点的距离。

Sample Input

6 9
1 2 1
1 3 12
2 3 9
2 4 3
3 5 5
4 3 4
4 5 13
4 6 15
5 6 4

Sample Output

0 1 8 4 13 17

code

详见注释

#include <iostream>
#define Max 503
#define INF 0xcffffff

using namespace std;

typedef struct AMGraph {							//定义图
	int vex, arc;
	int arcs[Max][Max];								//邻接矩阵
};

int dis[Max], path[Max];							//dis保存最短路径总权值、path通过保存路径的前驱结点来保存路径
bool book[Max];										//已找到最短路集合

void Dijkstra(AMGraph &G)							//迪杰斯特拉算法
{
	for (int i = 1; i <= G.vex; i++)				
	{
		dis[i] = G.arcs[1][i];						//初始化dis数组
		path[i] = dis[i] < INF ? 1 : -1;			//初始化路径数组
	}
	book[1] = true;									
	dis[1] = 0;										//起点初始化
	for (int i = 2; i <= G.vex; i++)				//遍历G.vex-1次
	{
		int mins = INF, u = 1;
		for (int j = 1; j <= G.vex; j++)			//找到当前没加入集合的最短路的后驱点
		{
			if (!book[j] && mins > dis[j]) {
				mins = dis[j];
				u = j;
			}
		}
		book[u] = true;								//将该点加入集合
		for (int j = 1; j <= G.vex; j++)			//遍历所有其他点对其最短路进行更新(松弛操作)
		{
			if (!book[j] && dis[j] > dis[u] + G.arcs[u][j]) {
				dis[j] = dis[u] + G.arcs[u][j];		//更新最短路径值
				path[j] = u;						//修改j的前驱为u
			}
		}
	}
}

void find(int x)									//递归输出最短路径
{
	if (path[x] == 1) {
		cout << 1;
	}
	else {
		find(path[x]);
	}
	cout << " -> " << x;
	return;
}

void putin(AMGraph &G)								//输入图
{
	cin >> G.vex >> G.arc;
	for (int i = 1; i <= G.vex; i++)				//初始化邻接矩阵
		for (int j = 1; j <= G.vex; j++)
			G.arcs[i][j] = INF;

	for (int i = 1; i <= G.arc; i++)			
	{
		int u, v, w;
		cin >> u >> v >> w;
		G.arcs[u][v] = w;
	}
}

void putout(AMGraph &G)								//输出
{
	//cout << "起点 v1 到各点的最短路程为: \n";
	for (int i = 1; i < G.vex; i++)
	{
		cout << dis[i] << " ";
	}
	cout << dis[G.vex] << endl;
	/*for (int i = 2; i <= G.vex; i++)
	{
		cout << "起点 v1 到 v" << i << " 的路径为: ";
		find(i);
		cout << endl;
	}*/
}

int main()
{
	AMGraph G;
	putin(G);
	Dijkstra(G);
	putout(G);
	return 0;
}

运行截图

去注释打印路径结果
Alt


蒟蒻一只,欢迎指正

  • 55
    点赞
  • 153
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值