1. 程式人生 > >基於C++的Dijkstra最短路徑演算法

基於C++的Dijkstra最短路徑演算法

#include "stdafx.h"
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<iostream>
#include<functional>
using namespace std;
const int maxn = 1e3;
const int INF = 1e9;
//int G[maxn][maxn];//鄰接表表示
int dis[maxn];//最短路
int vis[maxn] = { false };//標記頂點v是否已被訪問
int vertex, edge, start;//頂點,邊,起點
int pre[maxn];//pre[i]=u代表結點i的前驅為u
int num[maxn] = { 0 };//記錄最短路徑條數
struct node{
	int v;
	int routelen;
};
vector<node> adjacent[maxn];//鄰接矩陣表示
void dijkstra(int start) {//Dijkstra演算法
	fill(dis, dis + maxn, INF);//最短路徑初始化為無窮
	fill(pre, pre + maxn, -1);//初始化前驅
	dis[start] = 0;
	pre[start] = start;
	num[start] = 1;
	for (int i = 0; i < vertex; i++) {//迴圈n次
		int u = -1, min = INF;
		for (int j = 0; j < vertex; j++) {//尋找還未被訪問頂點的最短路
			if (dis[j] < min && vis[j] == false) {
				u = j;
				min = dis[j];
			}
		}
		if (u == -1) return;//如果沒找到,則return
		vis[u] = true;//如果找到,則置u被訪問
		for (int j = 0; j < adjacent[u].size(); j++) {//從u出發能夠到達的所有頂點
			int v = adjacent[u][j].v;
			if (vis[v] == false) {
				if (dis[u] + adjacent[u][j].routelen < dis[v]) {//v未被訪問&&以u為中介點能夠使得dis[v]更短
					dis[v] = dis[u] + adjacent[u][j].routelen;//更新路徑
					pre[v] = u;//更新前驅
					num[v] = num[u];//更新路徑條數
				}
				else if (dis[u] + adjacent[u][j].routelen == dis[v]) {//此處一定要用else if語句,不能用if,否則得到的num不正確
					num[v] += num[u];//更新路徑條數
				}
			}
		}
	}
}
void dfs(int a[],int k) {//遞迴輸出最短路徑
	if (a[k] == k) {
		printf("%d", k);
	}
	else if (a[k] == -1) {
		printf("無到達此點的路徑");
	}
	else {
		dfs(a, a[k]);//遞迴輸出前驅結點
		printf("->%d", k);//輸出本結點
	}
}
int main() {
	//fill(G[0], G[0] + maxn * maxn, INF);
	scanf("%d%d%d", &vertex, &edge, &start);
	int s, e, value;
	for (int i = 0; i < edge; i++) {
		int start, end, weight;
		scanf("%d%d%d", &start, &end, &weight);//分別輸入起點,終點,邊權
		node V;
		V.v = end;//v是邊的目標頂點
		V.routelen = weight;//邊權
		adjacent[start].push_back(V);
	}
	dijkstra(start);
	for (int i = 0; i < vertex; i++) {//輸出以start為源點,到達各大頂點的最短距離
		printf("%d ", dis[i]);
	}
	putchar('\n');
	int k;
	scanf("%d", &k);//輸入目標頂點k
	dfs(pre, k);//輸出源點到目標頂點k的最短路徑
	printf("\n%d", num[k]);//輸出源點到目標頂點的最短路徑條數
	return 0;
}


執行結果如下:

注意:Dijkstra最短路經演算法的時間複雜度主要是由外層迴圈O(V)和內層迴圈尋找最小的d(U)需要的O(V)、列舉V需要的O(adjacent[U].size)產生的,所以時間複雜度是O(V方+E),現在採用堆進行優化(最簡潔的做法就是採用STL庫裡的優先佇列進行優化),使複雜度降為O(vlogv+E),即O(vlogv)

當然,採用鄰接表的話,時間複雜度達到了O(V方)

Dijkstra是用來求解無負權圖的單源最短路徑問題。如果要求解帶有負權圖的單源最短路徑,則需要採用Bellman-Ford或SPFA演算法,Bellman-Ford演算法講解請看下節: