算法分析笔记:单源最短路径问题

问题描述

     给定带权有向图G =(V,E),其中每条边的权是非负实数。另外,还给定V中的一个顶点,称为源。现在要计算从源到所有其他各顶点的最短路长度。这里路的长度是指路上各边权之和。这个问题通常称为单源最短路径问题。


如图:

 解题思路:

设初始仅含有源顶点(起点)的集合s,设u是G的某一个顶点,把从源到u且中间只经过s中顶点的路称为从源到u的特殊路径,并用数组dist记录从源到每个顶点所对应的最短特殊路径,Dijkstra算法每次从V-s中取出具有最短特殊路径长度的顶点u,将u添加到S中,同时对dist数组做必要的修改。一旦s包含了所有V中的顶点,dist就记录了从源到所有其他顶点之间的最短路径长度。

所以基本流程是:判断最短从源到u的特殊路径-----》将u添加到集合s-----》更新dist[]值-----》重复以上流程直到s中包含所有顶点


使用Dijkstra算法的迭代过程


代码实现:

#include<iostream>
#include<iomanip>
#include<memory.h>
using namespace std;
#define N 100
#define maxint 99999
void Dijkstra(int n, int v, int dist[], int prev[],int c[][N]) {
	//n代表顶点个数
	//v为源点,即起点
	//prev[i]记录从源到顶点i的最短路径i的前一个顶点,无路可走时为0   
	//dist[i]表示当前从源到顶点i的最短特殊路径长度 
	//c[][]为邻接矩阵 
	int i, j;
	bool s[N];
	//初始化dist[]和prev[]
	for (i = 1; i <= n; i++) {
		dist[i] = c[v][i];//顶点v直接到顶点i的距离
		s[i] = false;
		if (dist[i] == maxint) {
			prev[i] = 0;
		}
		else {
			prev[i] = v;
		}
	}
	dist[v] = 0;
	s[v] = true;//v为源点
	//做n-1次贪心选择
	for (i = 1; i < n; i++) {
		int temp = maxint;
		int u = v;//u 是用记录刚刚最近添加到 已有集合s[]中的顶点
		//取出V-s中具有最短特殊路径长度的顶点u  
		for (j = 1; j <= n; j++) {//使用打擂台法,在剩下的路径长度中,选择当前状态下的最小值
			if ((!s[j]) && dist[j] < temp) {
				u = j;
				temp = dist[j];
			}
		} 
		s[u] = true;//将当前具有最短特殊路径长度的顶点u 添加到集合s[]中
		//根据做出的贪心选择更新dist值
		for (j = 1; j <= n; j++) {
			if ((!s[j]) && c[u][j] < maxint) {//当前加入的顶点u与j之间存在边
				int newdist = dist[u] + c[u][j];//计算源点v到u加上u点到j点的总长度 
				if (newdist < dist[j]) {//如果源点v经过刚添加的u点,到达j点更短的话,则需要更新
					dist[j] = newdist;
					prev[j] = u;
				}
			}
		}
	}
}

//输出最短路径
void Traceback(int start, int end, int prev[]) {
	if (start == end) {
		cout << end;
		return;
	}
	Traceback(start, prev[end], prev);
	cout << "->" << end;
}


int main() {
	int v = 1, n = 5, i, j;
	int dist[N], prev[N];
	int c[N][N] = {
		{0},
		{0,maxint,10,maxint,30,100},
		{0,maxint,maxint,50,maxint,maxint},
		{0,maxint,maxint,maxint,maxint,10},
		{0,maxint,maxint,20,maxint,60},
		{0,maxint,maxint,maxint,maxint,maxint}
	};
	cout << "每两个顶点之间的权值,即原始数据,从顶点1,1开始" << endl;
	cout << "有向图权的矩阵为:" << endl;
	for (i = 1; i <= n; i++) {
		for (j = 1; j <= n; j++) {
			if (c[i][j] == maxint) {
				cout << setw(5) << "无";
			}else {
				cout << setw(5) << c[i][j];
			}
		}
		cout << endl;
	}
	cout << "选择源点为: 1" << endl;
	Dijkstra(n, v, dist, prev, c);
	for (i = 1; i <= n; i++) {
		cout << "源点1" << "到点" << i << "的最短路径长度为:" << dist[i] << ",其路径为";
		Traceback(v, i, prev);
		cout << endl;
	}
	return 0;
}

 

 

  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值