最短路径之Dijkstra算法(邻接矩阵实现)

(一)Dijkstra算法

单源最短路径:就是从某一个顶点出发,到图中任意顶点之间的最短路径;
【算法概述】:Dijkstra算法适用于解决单源最短路径的问题。即:从源点到任意指定顶点之间的最短距离的问题;但Dijkstra算法要求所有边的权值非负。看过Prime算法的同学都知道,Dijkstra算法与Prime算法很相似,不同的就是dis数组的更新方式。Dijkstra算法用邻接矩阵存图比较方便。
【算法思想】:先用一个数组记录从源点到图中个顶点直接相连的距离,如果不直接连,就记录为无穷大,然后通过对该数组的更新,使得dis[x]表示从源点到x的最短路径;

在这里插入图片描述

如图:有四个顶点,6条边;求0到3直接的最短路径?由图得知是4,那么,如何用代码实现?
在这里插入图片描述

1.1 初始化
用邻接矩阵来存图,先进行初始化,自己到自己的距离初始化为0,到另外的顶点的距离初始化为无穷大。并将标记数组都置为0,表示所有顶点都未访问;

int mp[N][N];	//用邻接矩阵来存图;
int dis[N];		//用了记录源点到各顶点的距离;
int vis[N];		//标记顶点是否访问过;
void inin(int n)//初始化;
{
	int i,j;
	memset(vis, 0, sizeof(vis));
	for (i = 0; i < n; i++)
	{
		for (j = 0; j < n; j++)
		{
			if (i == j)
				mp[i][j] = 0;
			else
				mp[i][j] = INF;
		}
	}
}

1.2 Dijkstra主体
参数st表示源点,此题是0,n是顶点个数
第一步:先用dis数组储存与0直接相连的顶点之间的距离。并标记0号顶点;然后用一个while死循环来变量所有顶点,最坏的情况就是遍历所有顶点。
第二步:就是在当前的dis数组里找一个顶点没有访问过且距离源点最近的点,记录它的顶点下标;
第三步:更新dis数组:如果x顶点没有被访问,并且0到x顶点的距离(直接或间接)大于上面dis数组最小值加上点p到x点的距离,就对dis数组更新: dis[x] = min + mp[p][x];(可以理解为:从源点直接到某点的距离大于间接到某点的距离)
第四步:重复上面的第二步和第三步;
图示:
第一步:此时的dis数组:0 5 2 7;并标记源点0;此时的vis数组:1 0 0 0

这里是引用

第二步:找到最小距离2,p = 2;然后标记2号结点;此时的vis数组:1 0 1 0

这里是引用

第三步:更新dis数组,更新后为:0 5 2 4;

这里是引用

第四步:重复上面的第二步和第三步,直到所有的顶点都被访问;最后dis数组为:0 5 2 4;vis数组为:1 1 1 1

最后:
这里是引用

完整代码实现:

#include<iostream>
using namespace std;
#define N 1000
#define INF 0x3f3f3f3f
int mp[N][N];	//用邻接矩阵来存图;
int dis[N];		//用了记录源点到各顶点的距离;
int vis[N];		//标记顶点是否访问过;
void inin(int n)//初始化;
{
	int i,j;
	memset(vis, 0, sizeof(vis));
	for (i = 0; i < n; i++)
	{
		for (j = 0; j < n; j++)
		{
			if (i == j)
				mp[i][j] = 0;
			else
				mp[i][j] = INF;
		}
	}
}
void Dijkstra(int st,int n)//这里的st是源点,和prime算法中的st不同,这个不是任意的,而是根据题目要求的源点;
{
	int i, j, p;
	for (i = 0; i < n; i++)//用dis数组记录源点到与它相连接的顶点的距离;
	{
		dis[i] = mp[st][i];
	}
	vis[st] = 1;//标记刚才源点,表示已经访问;
	while (1)
	{
		p = -1;
		int min = INF;
		for (i = 0; i < n; i++)//在当前的dis距离数组中找到一个最小的路径,并将这条路到达的顶点记录;
		{
			if (vis[i] != 1 && dis[i] < min)
			{
				min = dis[i];
				p = i;
			}
		}
		vis[p] = 1;
		if (p == -1)//直到所有的顶点都已访问过,结束循环,当然,这是最坏的情况,如果在不考虑时间的情况下,可以这么写;
			break;
		for (i = 0; i < n; i++)//更新dis数组,
		{
			if (vis[i] != 1 && dis[i] > min + mp[p][i])
			{
				dis[i] = min + mp[p][i];
			}
		}
		
	}
	
}
int main()
{
	int n, m;
	int i, j;
	cin >> n >> m;//n个顶点,m条边
	inin(n);
	for (i = 0; i < m; i++)
	{
		int a, b, x;
		cin >> a >> b >> x;//a和b之间的距离是x
		mp[a][b] = x;//无向图;
		mp[b][a] = x;
	}
	int p, q;//求p到q之间的最短路径;
	cin >> p >> q;
	Dijkstra(p,n);
	cout << dis[q] << endl;
	return 0;
}

输入:
4 6
0 1 5
0 2 2
0 3 7
1 3 1
1 2 6
2 3 2
0 3
输出:
0到3的最短路径为:4
vis数组:1 1 1 1
dis数组:0 5 2 4

发布了59 篇原创文章 · 获赞 47 · 访问量 5518

猜你喜欢

转载自blog.csdn.net/qq_44755403/article/details/90415027
今日推荐