图的最短路径问题——Dijkstra算法的介绍

问题描述:
给定一个图G(V,E),求一条从起点到终点的路径,使得这条路径上经过的所有边的边权之和最小。

(这个问题PAT很容易考哦~)
解决最短路径问题的算法主要有:
Dijkstra算法,BF算法,SPFA算法,Floyd算法
不要求全部掌握啦,但是至少要熟悉一种哦~

接下来来讲第一种:Dijkstra算法~

Dijkstra算法:

这种算法一般用于解决***单源最短路问题***(给定G和起点s,通过算法得到S到达其他每个顶点最短距离)
算法基本思想:
对G设置集合S,存放已经被访问的顶点,然后每次从集合V-S中选择与起点s的最短距离最小的一个顶点(假设为u),访问并且加入集合S之后,令顶点u为中介点,优化起点s与所有从u能到达的顶点v之间的最短距离。这样操作n次,n为顶点个数,直到集合S已经包含所有顶点。

简单来说Dijkstra算法的策略就是:
设置集合S存放已经访问过的顶点,然后执行n次下面两个步骤:
1、每次从集合V-S(未访问过的顶点)中选择与起点s的最短距离中最小的一个顶点(记为u),访问并且加入集合S(即已访问)。
2、之后,令顶点u为中介点,优化起点s与所有从u能到达的顶点v之间的最短距离~

Dijkstra算法的具体实现:
1、集合S可以用一个bool类型的数组vis[]来实现,即当vis[i]=true的时候,表示顶点Vi已经被访问,当vis[i]==false的时候表示顶点Vi未被访问。
2、令int数组d[]表示起点s到达顶点Vi的最短距离,初始的时候除了起点s的d[s]赋为0,其余顶点都赋予一个很大的数,来表示inf,即不可达~

// 伪代码如下:
// G是图,一般设置为全局变量;
// d为源点到各个顶点的最短路径长度,s为起点
Dijkstra(G, d[], s){
	初始化;
	for(循环n次){
		u = 使d[u]最小的还没有被访问的顶点的符号;
		记录u已经被访问;
		for(从u出发能到达的所有顶点v){
			if(v未被访问过&&以u为中介点使得s到达顶点v的最短距离d[v]更优){
				优化d[v]}
		}
	}
}
// 定义全局变量
constint MAXV = 1000;
constint INF = 1000000000;

1、邻接矩阵模版:

int n, G[MAXV][MAXV];
int d[MAXV];
bool vis[MAXV] = {false};

void Dijkstra(int s){
	fill(d, d+MAXV, INF); // 将数组d全部赋值为INF
	d[s] = 0;
	for(int i = 0; i < n; i++){
		int u = -1, MIN = INF;//u使d[u]最小,MIN存放最小的d[u]
		for(int j = 0; j < n; j++){//找到未访问的顶点中d[u]最小的
			if(vis[j] == false && d[j] < MIN){
				u = j;
				MIN = d[j];
			}
		}
		//找不到小于INF的d[u],则说明剩下的顶点与s并不连通
		if(u == -1)	return;
		vis[u] = true;
		for(int v = 0; v < n; v++){
			if(vis[v] == false && G[u][v] != INF && d[u] + G[u][v] < d[v]){
				d[v] = d[u] + G[u][v];
			}
		}
	}
}

2、邻接表模版

struct Node{
	int v, dis;
}
vector<Node> Adj[MAXV];
int n;
int d[MAXV];
bool vis[MAX] = {false};

void Dijkstra(int s){
	fill(d, d+MAXV, 0);
	d[s] = 0;
	for(int i = 0; i < n; i++){
		int u = -1, MIN = INF;
		for(int j = 0; j < n; j++){
			if(vis[j] == false && d[j] < MIN){
				u = j;
				MIN = d[j];
			}
		}

		if(u == -1)	return;
		vis[u] = true;
		//只有下面这个遍历从u出发的所有顶点v的这个部分与邻接矩阵不同
		for(int j = 0; j < Adj[u].size(); j++){
			int v = Adj[u][j].v;
			if(vis[v] == false && d[u] + Adj[u][j].dis < d[v]){
				d[v] = d[u] + Adj[u][j].dis;
			}
		}
	}
}

当我们已经知道了最短距离如何实现,那么接下来来说说最短路径的实现方法~

只需要加一个pre[MAXV]即可~
看看如下算法模版~

int n, G[MAXV][MAXV];
int d[MAXV];
int pre[MAXV];// pre[v]就是从起点到顶点v的最短路径v上的前一个顶点
bool vis[MAXV] = {false};

void Dijkstra(int s){
	fill(d, d+MAXV, INF); // 将数组d全部赋值为INF
	//新添加,将pre[i]全部初始化其本身
	for(int i = 0; i < n; i++)	pre[i] = i;
	d[s] = 0;
	for(int i = 0; i < n; i++){
		int u = -1, MIN = INF;//u使d[u]最小,MIN存放最小的d[u]
		for(int j = 0; j < n; j++){//找到未访问的顶点中d[u]最小的
			if(vis[j] == false && d[j] < MIN){
				u = j;
				MIN = d[j];
			}
		}
		//找不到小于INF的d[u],则说明剩下的顶点与s并不连通
		if(u == -1)	return;
		vis[u] = true;
		for(int v = 0; v < n; v++){
			if(vis[v] == false && G[u][v] != INF && d[u] + G[u][v] < d[v]){
				d[v] = d[u] + G[u][v];
				pre[v] = u;
			}
		}
	}
}

这个仔细看起来有点像递归~
我们使用更简洁的递归方式:

void DFS(int s, int v){
	if(v == s){
		printf("%d\n", s);
		return;
	}
	DFS(s, pre[v]);
	printf("%d\n", v);//从最深层return回来之后,输出每一层递归的顶点号
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

艾尔伯特想变瘦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值