最短路径_Dijstra算法(单源)

定义
所谓最短路径问题是指:如果从图中某一顶点(源点)到达另一顶点(终点)的路径可能不止一条,如何找到一条路径使得沿此路径上各边的权值总和(称为路径长度)达到最小。

Dijkstra(迪杰斯特拉)算法
他的算法思想是按路径长度递增的次序一步一步并入来求取,是贪心算法的一个应用,用来解决单源点到其余顶点的最短路径问题。
//利用狄克斯特拉(Dijkstra)算法求上图中0结点到其它结点的最短路径,单源到单终点
//思想:某点到其他点的最短距离
//将N=(V,E)的所有顶点分成2个组合,第一组S:已经求出最小距离的点,起初只有v0,第二组:尚且为求出最短路径的终点集合
//按照各个顶点与v0间距递增的次序,逐个将V-S中的点加入S中,过程中要保持从v0到集合S各顶点的距离长度始终不大于到集合V-S中各顶点的距离长度
//算法辅助:带权的邻接矩阵,源点是v0
// 一维数组S[i]:记录从v0到vi是否已经被确定为最短路径长度,true表示确定
// 一维数组path[i];记录从源点到vi当前最短路径上的前驱:初始化:如果v0到vi有弧,则path[i]=v0,否则为-1
// 一维数组D[i]:记录从源点到vi的当前最短路径长度,初始化如果v0到vi有弧,则D[i]=弧上的权值,否则为无穷大
//S每加入一个点,多一个中转点
//假设v0到vi原来最小路径为D[i],加入vk后,以vk为中转的路径长度为D[k]+G.arc[k][i],if(D[i]>D[i]+G.arc[k][i])->D[i]=D[i]+D.arc[k][i]

//1图的邻接矩阵表示法和邻接表创建无向图存储

#include<iostream>
using namespace std;
#define MaxNum 100		//最大顶点数


//1.1图的邻接矩阵表示法创建无向图存储
#define MaxInt  32767	//无穷
typedef char VerType;//数据类型
typedef int ArcType;//权值类型
//图结构类型
typedef struct {
	VerType  v[MaxNum];//顶点表
	ArcType arc[MaxNum][MaxNum];//邻接矩阵
	int vernum, arcnum;	//点数,边数
}AMGraph;
//定位
int locate(AMGraph G, VerType v1) {
	for (int i = 0; i < G.vernum; i++) {
		if (G.v[i] == v1)
			return i;
	}
	return -1;
}
//创建无向图
bool createUDN(AMGraph &G) {
	cout << "Please input the vernum and arcnum" << endl;
	cin >> G.vernum >> G.arcnum;
	int i,j,p,q;
	VerType v1, v2;
	ArcType w;
	//初始化点的名字
	cout << "Please input the name of vernum in order " << endl;
	for (i = 0; i < G.vernum; i++) cin >> G.v[i];
	//初始化邻接矩阵
	for (i = 0; i < G.vernum; i++) {
		for (j = 0; j < G.vernum; j++) {
			if (i != j)
				G.arc[i][j] = MaxInt;
			else
				G.arc[i][j] = 0;
		}
	}
	//开始操作,构造邻接表
	cout << "Please input arcnum graph " << endl;
	for (i = 0; i < G.arcnum; i++) {
		cin >> v1 >> v2 >> w;
		p = locate(G, v1); q = locate(G, v2);
		G.arc[p][q] = w;
		G.arc[q][p] = G.arc[p][q];
	}
	return true;
}
void show(AMGraph G) {
	int i, j;
	for (i = 0; i < G.vernum; i++) {
		for (j = 0; j < G.vernum; j++) {
			if (G.arc[i][j] == MaxInt)  printf("INF\t");
			else printf("%-3d\t", G.arc[i][j]);
		}
		cout << endl;
	}
}

//Dijkstra展示
//利用递归,找到前驱等于自己的点,递归返回输出后继结点

void showCircle(AMGraph G,int path[], int v0, int u) {
	if (u == v0) {
		cout << G.v[u]<< " ";
		return;
	}
	else
		showCircle(G,path, v0, path[u]);
	cout << G.v[u] << " ";
}

//算法辅助:带权的邻接矩阵,源点是v0
// 一维数组S[i]:记录从v0到vi是否已经被确定为最短路径长度,true表示确定
// 一维数组path[i];记录从源点到vi当前最短路径上的前驱:初始化:如果v0到vi有弧,则path[i]=v0,否则为-1
// 一维数组D[i]:记录从源点到vi的当前最短路径长度,初始化如果v0到vi有弧,则D[i]=弧上的权值,否则为无穷大

void ShortPath_DIJ(AMGraph G,int v0) {
	
	bool *S = new bool[G.vernum];
	int * path = new int[G.vernum];
	int *D = new int[G.vernum];
	memset(path, 0, sizeof(path));
	//初始化
	int i = 0, n = G.vernum,w=0;
	for (i = 0; i < n; i++) {
		S[i] = false;		//点入集合的标志数组
		D[i] = G.arc[v0][i];//v0到i点的最短路径长度,起初为弧上权值
		if (D[i] < MaxInt)		path[i] = v0;//与v0有弧
		else path[i] = -1;
	}
	S[v0] = true;//将v0加入S
	D[v0] = 0;
	int v = -1;
	//初始化结束,开始主循环,每次求得v0到某个点vi的最短路径,将vi加入S
	for (i = 1; i < n; ++i) //列
	{
		ArcType min = MaxInt;
		for (w = 0; w < n; ++w){ //行
			if (!S[w] && D[w] < min) {
				min = D[w];
				v = w;//选择当前最短路径终点v
			}
		}
			S[v] = true;//将v加入S中的标志
			for (w = 0; w < n; ++w) {//更新从v0出发到V-S上所有的顶点的最短路径长度
				if (!S[w] && (D[v] + G.arc[v][w] < D[w])) {
					D[w] = D[v] + G.arc[v][w];
					path[w] = v;			//最短路径前驱是v
				}
		}
}
	cout << "Please input the source and destination" << endl;
	char ch1, ch2;
	while (cin >> ch1 >> ch2) {
		v = locate(G, ch1); w = locate(G, ch2);
		showCircle(G,path,v,w );
		cout << "length=" << D[w] << endl;
		cout << endl;
		cout << "Please input the source and destination" << endl;
	}
	delete[]S;
	S = NULL;
	delete[]path;
	path = NULL;
	delete[]D;
	D= NULL;
}
int main() {
	AMGraph G;
	createUDN(G);
	show(G);
	ShortPath_DIJ(G,0);
}

我这里只是给代码实现,想动态地了解,推荐下面这篇的(有图片介绍)
https://blog.csdn.net/lbperfect123/article/details/84281300

发布了122 篇原创文章 · 获赞 14 · 访问量 6197

猜你喜欢

转载自blog.csdn.net/weixin_44001521/article/details/103714681
今日推荐