详解 Dijkstra迪杰斯特拉算法

摘要:

描述:单源 最短路径(找到指定顶点到其余各点的最短路径)
思想:greedy

复杂度:

时间复杂度:O(n^2)
空间复杂度:O(n)

思想概要:

关键:每次将V-U内到起点最短的顶点加入到U,并且尝试作为中转点,缩短起点到V-U其他顶点的距离
  这样做,下一条构成的路径(设终点为x),必然是v0到vx的最短路径,且必定是b2或者是B1+b2。即,v0到vx的最短路径不会是通过A1 + a2 + A3这种方法产生的

辅助图解:

U表示已找出的,从v0出发的,最短路径的终点;V-U是待找出的

1:所有顶点都在U内的路径;
2:连通U和V-U的弧
3:所有顶点都在V-U内的路径;
Vx表示顶点,
a2表示某条连通U和V-U的弧
A1表示连通起点到弧a2的在U里的顶点的路径
A3表示连通弧a2的在V-U里的顶点到终点的路径

图示顶点加入原则

证明:

简要证明:
  按照这个过程,会存在一条比b2/B1+b2算法更短的路径,那就只能是A1 + a2 + A3,而A1 + a2 + A3比b2/B1+b2小意味着a2必须小于b2,但这与b2的语义(b2是当前连通U和V-U最短的弧) 相矛盾

详细证明:(反证法:要证v0到x可能是通过A1 + a2 + A3产生的)
  假设v0到x的最短路径的构成是成分是A1 + a2 + A3,则A1 + a2 + A3必然小于b2,且A1 + a2 + A3必然小于任意一条B1+b2。
如果A1 + a2 + A3 < b2,那么A1,a2,A3三个成分至少有一个是小于b2的。
  然后你就突然发现,只要允许路径权值和为负值的话,这没有任何毛病,没办法反证!!只有所有弧的权值>=0证明才能成立。
 在所有弧的权值都>=0前提下
》对于A1 + a2 + A3 < b2的推论:
A1,a2,A3必须都小于b2,但既然a2<b2,按照约定的算法,下一条被加入的弧应该是a2而不是b2,与算法事实相矛盾
》对于A1 + a2 + A3 < B1 + b2的推论:
如果有A1 + a2 + A3 小于任意一条 B1+b2,就有A1 + a2 < B1+b2,意味着U中任意一个顶点到x的距离都大于a2(即存在另一条弧,比选定的将加入弧更小,因此这次选择是错误的),但按照算法约定,a2才是下一个被加入的弧

我最大的疑惑:

1.最小生成树的任意两点之间的路径是不是连通这两点的最短路径?(这也是Dijkstra跟Prim的区别所在)
答:不是,由下图可知,A{<v0,v1>,<v1,v2>,<v2,v3>}和B{<v0,v1>,<v1,v3>,<v2,v3>}都是最小生成树,但A中从v0到v3路径长6,B中v0到v3路径长4
MST路径不等于最短路径
2.在将顶点从V-U加入到U过程中,是选择v0到V-U最短的路径,还是选择U到V-U最短的路径
答:选择v0到V-U最短的路径,道理同上,如果只考虑U到V-U而不从这条路径考虑,遇到这种<v1,v2>和<v0,v3>弧相等的情况就没办法准确的抉择

路径的选择
3.(假设在一个连通图里)按迪杰斯特拉方法将某点到其余所有顶点的最短路径都建立完后,是不是一棵最小生成树
(假设在一个无向连通图里)首先最短路径都建立完后,肯定是一个连通图,因为所有点都和v0连通,而连通是可传递的
其次,它肯定是一棵生成树,否则它必定有环(连通但不是极小意味着有环)但这跟“只要顶点被加入U,v0到它的最短路径就已经被找到”的结论不符合
然后它也是最小生成树。假设它不是MST,
解释1:那么在v0到达某点vx之间必定存在另一条更短的路径,但这是不可能大,正如上面说,如果这另一条是v0直达vx的,就一定是“选V-U中v0到它路径最短的点”的结果;如果是其他点v间接到达的,因为v0到v肯定比v0到vx更快,所以v必然在vx之前就加入到U了
解释2:那么某点vx被加入U时选择的必然是另一条更短的路径,且并非B1+b2或b2产生的结果;
那就只能是A1+a2+A3这种方法的结果了,但这样被a2连通的节点必定先于vx被加入U,也就是说,实际上会演变成B1+b2的情况

=====================================================================

实现:

注意,迪杰斯特拉的完整过程,是找到一个起点到其余所有顶点的最短路径,如果只希望找到指定终点的最短路径,最糟糕的情况下,需要先找到前面所有顶点的最短路径

其实,Dijkstra和Prim的思想十分类似,都是贪心算法的思想,我自己想的时候,都是先将需要的数据准备好。但这两种方法的精妙之处,就在于需要的数据是一边更新状态一边获取的。


#define INF INT_MAX

struct Edge
{
	int b, e, w;
	Edge() :b(-1), e(-1), w(-1) {}
	Edge(int begin, int end, int weight) :b(begin), e(end), w(weight) {}
};

struct AdjMatrix
{
	int vn, en;
	vector<vector<int>> m;
	AdjMatrix(const vector<vector<int>>& mat)
	{
		m = mat;
		vn = mat.size();
	}
};

list<Edge> Dijkstra(const AdjMatrix& mat, int src, int dst)
{
	if (mat.vn <= 0) return list<Edge>();
	if (src == dst) return list<Edge>{Edge(src,src,0)};
	int n = mat.vn;
	list<Edge> path;
	vector<bool> vs(n, false);
	vector<int> prev(n, src);
	vector<int> minArc(n, INF);
	minArc[src] = 0;
	vs[src] = true;
	prev[src] = -1;
	int k = 1;
	int v = src;
	while (k <= n - 1)
	{
		int minw = INT_MAX;
		int nextv = -1;
		for (int i = 0; i < n; ++i)
		{
			if (vs[i]) continue;
			if ((mat.m[v][i] != INF) && (minArc[v] + mat.m[v][i] < minArc[i])) // 前提是可达
			{
				minArc[i] = minArc[v] + mat.m[v][i];
				prev[i] = v;
			}
			if (minArc[i] < minw)
			{
				minw = minArc[i];
				nextv = i;
			}
		}
		if (nextv == -1) break;
		v = nextv;
		vs[v] = true;
		if (v == dst) break;
		++k;
	}
	if (v == dst) // 回溯构建路径
	{
		int pv, cur = dst;
		do {
			pv = prev[cur];
			path.push_front(Edge(pv, cur, mat.m[pv][cur]));
			cur = pv;
		} while (pv != src);
	}

	return path;
}

TestCase:


int main()
{
	vector<vector<int>> m{
		{INF,4,INF,INF,2},
		{4,INF,INF,INF,INF},
		{INF,INF,INF,1,3},
		{INF,INF,1,INF,INF},
		{2,INF,3,INF,INF},
	};
	AdjMatrix mat(m);
	auto l = Floyd(mat);

	getchar();
	return 0;
}

参考

【1】https://www.geeksforgeeks.org/dijkstras-shortest-path-algorithm-using-priority_queue-stl/
【2】https://www.geeksforgeeks.org/widest-path-problem-practical-application-of-dijkstras-algorithm/

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Dijkstra迪杰斯特拉算法是一种典型的最短路径算法,可以用于计算一个节点到其他节点的最短路径。它的主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止,使用的是广度优先搜索的思想。该算法通过不断更新起始点到其他节点的距离,选择当前距离最短的节点进行扩展,直到所有节点都被扩展完毕,找到起始点到其他节点的最短路径。Dijkstra算法在网络路由、地图导航等领域有广泛应用。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [C++实现Dijkstra(迪杰斯特拉)算法](https://download.csdn.net/download/weixin_38692122/12724830)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [Dijkstra(迪杰斯特拉)算法](https://blog.csdn.net/qq_43461641/article/details/100632351)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [DijkstraAlgorithm(迪杰斯特拉算法)](https://blog.csdn.net/qq_45740348/article/details/113575420)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值