基于Dijsktra算法的最短路径求解

基于Dijsktra算法的最短路径求解

1.问题描述:
一张地图包括n个城市,假设城市间有m条路径(有向图),每条路径的长度已知。给定地图的一个起点城市和终点城市,利用Dijsktra算法求出起点到终点之间的最短路径。


2.输入要求:
多组数据,每组数据有m+3行。第一行为两个整数n和m,分别代表城市个数n和路径条数m。第二行有n个字符,代表每个城市的名字。第三行到第m+2行每行有两个字符a和b和一个 整数d,代表从城市a到城市b有一条距离为d的路。最后一行为两个字符,代表待求最短路径的城市起点和终点。当n和m都等于0时,输入结束。


3.输出要求:
每组数据输出2行。第1行为一个整数,为从起点到终点之间最短路的长度。第2行为一串字符串,代表该路径。每两个字符之间用空格隔开。

 

实现代码如下(含有部分代码注释解释):

#include <iostream>
#include<string>
using namespace std;

//____图的邻接矩阵存储表示____
#define MaxInt 32567 //表示极大值,即正无穷
#define MVNum 100 //最大定点数
#define OK 1
typedef char VerTexType;//假设顶点的数据类型为字符型 vertex顶点
typedef int ArcType;//假设边的权值类型为整型
typedef struct 
{
	VerTexType vexs[MVNum];//顶点表
	ArcType arcs[MVNum][MVNum];//邻接矩阵(其中arcs[v1][v2]的值应当于arcs[v2][v1]相等,在矩阵中呈对称形式,但是对应的是同一个边,所以权值相同)
	int vexnum, arcnum;//图的当前点数和边数
}AMGraph;

VerTexType IndexVex(AMGraph G, int u) 
{//存在则返回u在顶点表中的下标,否则返回-1
	return G.vexs[u];
}

int LocateVex(AMGraph G, VerTexType v) 
{
	for (int i = 0; i < G.vexnum; i++) 
	{
		if (v == G.vexs[i])//输入的顶点v在G中找到
			return i;  //返回顶点在图中所在的位置
	}
	return -1;
}

//创建无向图
int CreateUDN(AMGraph& G) 
{
	//采用邻接矩阵表示法,创建无向网G
	char v1, v2;
	int w;
	cin >> G.vexnum >> G.arcnum;//输入总顶点数,总边数
	for (int i = 0; i < G.vexnum; ++i)
		cin >> G.vexs[i]; //为无向网中的顶点赋值
	for (int i = 0; i < G.vexnum; ++i)//初始化邻接矩阵,边的最大权值设置为极大值MaxInt
		for (int j = 0; j < G.vexnum; ++j)
			G.arcs[i][j] = MaxInt; //先将边的初始权值均设置为最大值
	int i, j;
	for (int k = 0; k < G.arcnum; ++k) {//构造邻接矩阵
		cin >> v1 >> v2 >> w;//输入一条边依附的顶点及权值 (一条边对应两个顶点以及自身的一个权值)
		//分别将v1,v2在顶点数组中的位置赋值给i,j
		i = LocateVex(G, v1);
		j = LocateVex(G, v2);
		G.arcs[i][j] = w;//边<v1,v2>的权值置为w
		G.arcs[j][i] = G.arcs[i][j];//置<v1,v2>的对称边<v2,v1>的权值为w
	}//for
	return OK;
}

//创建有向图
int CreateDN(AMGraph& G, int vex, int edge)  //vex对应的为地点数,edge对应的是路径数
{
	//采用邻接矩阵表示法,创建有向网G
	char v1, v2;
	int w;
	//cin >> G.vexnum >> G.arcnum;//输入总顶点数,总边数
	//从外部获取总顶点数和总边数(创建无向图的时候是在函数内部输入图的总顶点数和总边数)
	G.vexnum = vex;//总顶点数
	G.arcnum = edge;//总边数
	//顶点的初始化以及边的初始化类似于无向图的处理
	//输入所有的地点
	cout << "请输入" << vex << "个地点:" << endl;
	for (int i = 0; i < G.vexnum; ++i)
		cin >> G.vexs[i]; 
	for (int i = 0; i < G.vexnum; ++i)//初始化邻接矩阵,边的最大权值设置为极大值MaxInt
		for (int j = 0; j < G.vexnum; ++j)
			G.arcs[i][j] = MaxInt;
	int i, j;
	//输入所有的路径
	cout << "请输入" << edge << "条路径:" << endl;
	for (int k = 0; k < G.arcnum; ++k) 
	{
		//构造邻接矩阵
		cin >> v1 >> v2 >> w;//输入一条边依附的顶点及权值
		i = LocateVex(G, v1);
		j = LocateVex(G, v2);//确定v1和v2在G中的位置,即顶点数组的下标
		G.arcs[i][j] = w;//边<v1,v2>的权值置为w (因为是有向图,所以G.arcs[i][j]和G.arcs[j][i]代表的就不是同一条边了)
		//G.arcs[j][i] = G.arcs[i][j];//置<v1,v2>的对称边<v2,v1>的权值为w
	}//for
	return OK;
}

/*
* 迪杰斯特拉算法的实现
* 假设用带权的邻接矩阵arcs来表示带权有向网G,G.arcs[i][j]表示弧<vi,vj>上的权值。
* 若<vi,vj>不存在,则置G.arcs[i][j]为无穷大,源点v0
* 算法的实现要引入以下辅助的数据结构
* ①一维数组S[i]:记录从源点v0到终点vi是否已被确定最短路径长度,true表示确定,false表示尚未确定
* ②二维数组Path[i]:记录从源点v0到终点vi的当前最短路径上vi的直接前驱顶点序号。
* 其初值为:如果从v0到vi有弧,则Path[i]为v0;否则为-1
* ③一维数组D[i]:记录从源点v0到终点vi的当前最短路径上vi的当前最短路径长度。其初值为:如果从v0
* 到vi有弧,则D[i]为弧上的权值;否则为正无穷
*/
int D[MVNum], Path[MVNum];
void ShortestPath_DIJ(AMGraph G, VerTexType V) 
{
	//用Dijkstra算法求有向网G的v0顶点到其余顶点的最短路径
	int n, w, v, min;
	int S[MVNum]; //用于记录源点V0到重点Vi是否被确定为是最短路径长度
	n = G.vexnum;//n是顶点的个数
	int v0 = LocateVex(G, V);
	for (v = 0; v < n; v++) 
	{
		S[v] = false;//S初始为空集(
		D[v] = G.arcs[v0][v];//将v0到各个终点的最短路径长度初始化为弧上的权值 (依次遍历顶点集数组,将于v0直接连通的对应的权值保存在数组D对应的位置)
		if (D[v] < MaxInt) 
		{
			Path[v] = v0;//如果v0和v之间有弧,则将v前驱置为v0
		}
		else 
		{
			Path[v] = -1;//如果v0和v之间无弧,则将v前驱置为-1
		}
	}//for
	S[v0] = true;//将v0加入S (意味着到V0的最短距离就是V0-V0)
	D[v0] = 0;//源点到源点的距离为0
	/*————————初始化结束,开始主循环,每次求得v0到某个顶点v的最短路径,将v加到S集————————*/
	//共n个顶点,除去首顶点v0,还需要循环n-1次(对应n-1个节点)
	for (int i = 1; i < n; i++)  //顶点集从0~n-1(n=G.vexnum)
	{
		//对其余n-1个顶点,依次进行计算
		min = MaxInt;
		for (w = 0; w < n; ++w) 
		{

			if (!S[w] && D[w] < min)  // 判定条件: !S[w]即S[w]=false,意味着此时V0到W还没有被确定为最短路径,第二个条件D[w]<min用于筛选出所有V0到所有节点中的最小值(即权值最小)
			{

				v = w; //用于记录保存V值
				min = D[w];//选择一条当前的最短路径,终点为v 
			}
		}
		S[v] = true;//将v加入S
		for (w = 0; w < n; w++) 
		{
			//更新从v0出发到集合V-S上所有顶点的最短路径长度
			if (!S[w] && (D[v] + G.arcs[v][w] < D[w]))  //D[w]是从v0直接到w顶点的距离,而D[v]+G.arcs[v][w]则是从v0到v,再从v到w的距离
			{
				D[w] = D[v] + G.arcs[v][w];//更新D[w]
				Path[w] = v;//更改w的前驱为v (v0->v->w)
			}//if
		}
	}//for
}

//输出从起点到终点中通过的地点(包含起点,不包含终点)
void Search(AMGraph G, int v) 
{
	if (Path[v] == -1) //递归的出口:不存在弧
		return;
	else 
	{
		//递归直到两个顶点间不存在弧
		Search(G, Path[v]);
		cout << IndexVex(G, Path[v]) << "->"; //输出顶点
	}
}

int main() {
	char city1, city2;//城市名字,起点、终点
	int a, b;//n个地点,m条路径
	cout << "输入地点数目(重庆邮电大学中的地点)以及路径数: " << endl;
	while (cin >> a >> b && a && b) 
	{
		AMGraph G; 
		CreateDN(G, a, b); //创建有向图 其中包含过程 cin >> G.vexs[i];即输入地点(顶点) cin >> v1 >> v2 >> w; 输入两个地点以及这两个地点之间的路径(即两个顶点以及两个顶点间的权重)
		cout << "请输入起始位置:" << endl;
		cin >> city1;
		ShortestPath_DIJ(G, city1);
		cout << "请输入终点位置:" << endl;
		cin >> city2;
		int n = LocateVex(G, city2);
		cout << "最短路径长度为:" << endl;
		cout << D[n] << endl;
		cout << "最短路径为:" << endl;
		Search(G, n);
		cout << city2 << endl;

		cout << "请继续输入地点数目以及路径数(输入0 0退出)" << endl;
	}
	return 0;
}

程序运行结果:

  • 7
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值