数据结构(C++)Dijkstra算法

改了两天的Dijkstra算法,最后我发现我把有向图一直当成无向图在做,多写了一行代码,结果卡了三天,耽误了太多的时间了。

Dijkstra算法,求一个顶点到另一个顶点的最短路径长度,并且保存下来路径。用标准语言来形容是:
再网图中,最短路径是指两个顶点之间经历的边权之值之和的最短路径。时间复杂度是O (n 2)

基本思想:

  1. 设置一个集合S存放已经找到最短路径的顶点,S的初始状态只包含源点v,
  2. 对vi∈V - S,假设从源点v到vi的有向边为最短路径(从v到其余顶点的最短路径的初值)。
  3. 以后每求得一条最短路径v, …, vk,就将vk加入集合S中,并将路径v, …, vk, vi与原来的假设相比较,取路径长度较小者为最短路径。

重复上述过程,直到集合V中全部顶点加入到集合S中。

路径长度最短的最短路径(即第一条最短路)的特点:在这条路径上,必定只含一条边,并且这条边上的权值最小。

下一条路径长度次短的最短路径的特点:它只可能有两种情况:或者是直接从源点到该点(只含一条边)。或者是从源点经过顶点v1(第一条最短路径所依附的顶点),再到达该顶点(由两条边组成)。

再下一条路径长度次短的最短路径的特点:它可能有四种情况:或者是直接从源点到该点(只含一条边); 或者从源点经过顶点v1,再到达该顶点(由两条边组成);或者是从源点经过顶点v2,再到达该顶点(两条条边);或者是从源点经过顶点v1、v2,再到达该顶点(多条边)。

其余最短路径的特点:它或者是直接从源点到该点(只含一条边); 或者是从源点经过已求得最短路径的顶点(集合S中的顶点),再到达该顶点。

尽量看懂上面的四个特点,没看懂说明没尽量。

Dijkstra基本思想

辅助数组
  1. dist[MaxSize]数组,是用来保存从固定一个顶点向其他所有的点连通路的最小边权。
  2. path[MaxSize]数组,存储路径,表示该点的下一个顶点位置。
  3. visited[MaxSize]数组,存储该点是否已经被访问过。

Dijkstra算法实现代码

  1. 第一步,为dist赋初值,为第一个顶点与之相连接边的权值,不连通则赋值无穷大。访问数组全部赋值0,都没有被访问。path数组初值-1 。
  2. 循环n-1次,找到n-1条路径。每次循环的内容是:找到dist中最短的那条边,然后记录位置,使这个位置成为这一次循环确定的最短通路。
  3. 然后把这条边加入到已经确定的通路集合里,遍历其他所有的顶点,进行松弛操作,若新点与之连接比之前连接的顶点短,则更新dist数组。
  4. 最后的输出利用的栈,因为想要使从开头走向结尾,如果想要反向,则去掉栈就可以。
#include<iostream>
#include<stack>
using namespace std;
const int MaxSize = 20;
const int INF = 9999;
int dis[MaxSize];
int visited[MaxSize];
int path[MaxSize];
class MGraph
{
	int arcNum;
	int vertexNum;
	int arc[MaxSize][MaxSize];
public:
	MGraph(int n, int e)
	{
		arcNum = e;
		vertexNum = n;
		for (int i = 0; i < vertexNum; ++i)
		{
			for (int j = 0; j < vertexNum; ++j)
			{
				if (i == j)
					arc[i][j] = 0;
				else
					arc[i][j] = INF;
			}
		}
		for (int i = 0; i < arcNum; ++i)
		{
			int a, b, v;
			cin >> a >> b >> v;
			arc[a][b] = v;
		}
	}
	void Dijkstra(int v)
	{
		for (int i = 0; i < vertexNum; ++i)
		{
			dis[i] = arc[v][i];
			visited[i] = 0;
			path[i] = -1;
		}
		visited[v] = 1;
		for (int i = 0; i < vertexNum; ++i)
		{
			int min = INF;
			int k = 0;
			for (int j = 0; j < vertexNum; ++j)
			{
				if (min > dis[j] && visited[j] == 0)
				{
					min = dis[j];
					k = j;
				}
			}
			visited[k] = 1;
			for (int j = 0; j < vertexNum; ++j)
			{
				if (visited[j] == 0 && dis[j] > dis[k] + arc[k][j])
				{
					dis[j] = dis[k] + arc[k][j];
					path[j] = k;
				}
			}
		}
	}
};
int main()
{
	int x, y;
	cin >> x >> y;
	int s, e;
	cin >> s >> e;
	MGraph G(x, y);
	G.Dijkstra(s);
	if (dis[e] == INF)
		cout << "no answer" << endl;
	else
	{
		cout << dis[e] << endl;
		cout << "v" << s << " ";
		int p = e;
		stack<int>st;
		while (path[p] != -1)
		{
			st.push(path[p]);
			p = path[p];
		}
		while (!st.empty())
		{
			cout << "v" << st.top() << " ";
			st.pop();
		}
		cout << "v" << e;
	}
	return 0;
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值