使用邻接矩阵+Dijkstra算法求解单源最短路径问题

Dijkstra算法是求解有向非负带权图中某一结点到其它结点的最短路径算法。这个算法和Prim算法求解最小生成树有点相似,它也是先有一个初始顶点,然后查找最小带权路径。

不同的是,Prim需要更新最小生成树的结点,不断将结点更新到VT中,然后更新low_cost[]数组,是VT中的各结点到V-VT中的各结点的最小路径。

而Dijkstra算法更新的dist[]数组,仅仅是源点到其他点的最短路径,不需要记录VT,但可以添加path数组或容器,记录其路径。算法结束时,dist[]数组即记录了源点到其它各点的最短路径,时间复杂度为O(|V|²)

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

typedef struct{
	int vexnum;	//顶点数 
	int arcnum;	//边数 
	unsigned **arc;	//邻接矩阵
	string *name; 
}Matrix_Graph;	

bool newGraph(Matrix_Graph& g)
{
	cout << "-------准备使用邻接矩阵法创建有向带权图-------" << endl;
	cout << "请输入顶点数和边数(空格隔开): ";
	cin  >> g.vexnum >> g.arcnum;
	//	图可以没有边,但不能没有顶点
	//	若有向图有n个顶点,则最多有n*(n-1)条边(有向完全图) 
	if( g.vexnum<0 || g.arcnum<=0 || g.arcnum>g.vexnum*(g.vexnum-1) ){
		cerr << "数据输入有误,请检查数据!" << endl; 
		g.vexnum = g.arcnum = 0;
		return false;
	}
	//	邻接矩阵初始化 
	g.arc  = new unsigned*[g.vexnum+1];
	g.name = new string[g.vexnum+1]; 
	for(int i = 1; i <= g.vexnum; ++i){
		g.name[i] = "V" + to_string(i);	//从1开始计数,边为V1, V2, V3... 
		g.arc[i]  = new unsigned[g.vexnum+1];
		for(int j = 1; j <= g.vexnum; ++j)
			g.arc[i][j] = INT_MAX;		//各边距离初始化为无穷大	
	}
	//	输入各边的权值
	int vstart, vend, weight;
	int n = g.arcnum;
	cout << "请输入" << n << "条有向边的起始顶点、终止顶点和权值(空格隔开)" << endl; 
	while( n-- ){
		cin >> vstart >> vend >> weight;
		g.arc[vstart][vend] = weight;	//有向图		
	}	 
	
	return true;		
}
void printRes(vector<string>& path, int *dist, int start)
{
	cout << "当前路径为:"; 
	for(auto s : path)
		cout << s << ", ";
	cout << endl;
	
	cout << "源点到各点的最短路径值:" << endl; 
	for(int i = 1; i <= dist[0]; ++i){
		cout << "V"+to_string(start) << "->" << "V"+to_string(i) << ": ";
		if( dist[i] == INT_MAX )
			cout << "∞ ";
		else
			cout << dist[i] << " ";
		cout << endl;	 	
	}
	cout << endl;	
}

bool Dijkstra(const Matrix_Graph& g, int start = 1)
{
	int  i, j, k;
	//	存储源点到其它顶点的最短路径长度 
	int  dist[g.vexnum+1];
	for(i = 1; i <= g.vexnum; ++i)
		dist[i] = g.arc[start][i];
	dist[0] = g.vexnum;	
	//	存储已经访问过的结点 
	bool visited[g.vexnum+1] = {false};
	visited[start] = true;
	//	存储路径 
	vector<string> path;	//VT
	path.push_back( g.name[start] );
	
	int n = g.vexnum-1;
	while( n-- )
	{
		printRes(path, dist, start);
		int min = INT_MAX;
		//	找出dist[]中的最小权值顶点Vj 
		for(i = 1; i <= g.vexnum; ++i){
			if( !visited[i] && dist[i]<min ){
				min = dist[i];
				j = i;
			}
		}
		visited[j] = true;	
		path.push_back( g.name[j] );
		//	更新dist[] 
		for(k = 1; k <= g.vexnum; ++k){
			//	若源点到Vj的距离+Vj到Vk的距离
			//	小于源点到Vk的距离,更新
			//	至少有一个用unsigned存储,否则可能会上溢 
			if( dist[j]+g.arc[j][k]	< dist[k] )
				dist[k] = dist[j]+g.arc[j][k];	
		}	
	}	
	cout << "-------最后的结果是-------" << endl;	
	printRes(path, dist, start);
}
 
int main()
{    
    Matrix_Graph g;
    if( newGraph(g) ){
    	Dijkstra(g);
    } 
	
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Love_Irelia97/article/details/82701408
今日推荐