1. 程式人生 > 其它 >圖論最短路演算法小結

圖論最短路演算法小結

主要來講3種
\(1\).\(Dijkstra\)
\(Dijkstra\)是用一種類似貪心的想法來完成最短路
看下面的有向圖:

我們設\(1\)為整個圖的起點,要求出\(1\)到所有點的最短路
\(1\)開始,\(1\)\(1\)的最短路為0
遍歷\(1\)所有指向的邊:\(2, 3, 4, 5\)
其中最小值\(1 \rightarrow 3\)這條邊的權值為\(1\)
接下來更新所有的最短路路徑,用\(dis\)表示
\(dis[1] = 0, dis[2] = 3, dis[3] = 1, dis[4] = 6, dis[5] = 2\)
那麼,\(1\)\(3\)的最短路一定為\(1\)


這是已經確定的最短路
遍歷,尋找已經確定的最短路。怎麼尋找?就是\(dis\)最小的那個,找出來為\(3\)
再一次重複上面的步驟
遍歷\(3\)所有指向的邊:\(2, 4\)
更新所有的最短路路徑
\(dis[2] = dis[3] + 1 = 2, dis [4] = dis[3] + 4 = 5\)
然後\(1\)\(2\)的最短路又確定了
就這麼不斷重複,直到確定所有的最短路
模板題目
程式碼實現:

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e4 + 5;
const int INF = INT_MAX;
typedef pair <int, int> PII;
#define mp make_pair
int n, m, s, u, v, w, d[MAXN];
vector <PII> G[MAXN];
bool vis[MAXN];
void dijkstra() {
	for (int i = 1; i <= n; ++i) {
		int minn = -1;
		for (int j = 1; j <= n; ++j) {
			if (vis[j]) continue; //這個點的最短路已經確定,不用再更新了
			if (minn == -1 || d[j] < d[minn]) minn = j;
		}
		if (d[minn] == INF) continue; //特判一下,不然INF + 其他數會溢位
		vis[minn] = 1;
		for (vector <PII> :: iterator it = G[minn].begin(); it != G[minn].end(); ++it) {
			int f = it -> first, s = it -> second;
			d[f] = min(d[f], d[minn] + s);
		}
	}
}
int main() {
	scanf("%d%d%d", &n, &m, &s);
	for (int i = 1; i <= m; ++i) 
		scanf("%d%d%d", &u, &v, &w), G[u].push_back(mp(v, w));
	for (int i = 1; i <= n; ++i) d[i] = INF;
	d[s] = 0;
	dijkstra();
	for (int i = 1; i <= n; ++i) printf("%d ", d[i]); 
	return 0;
}

上面程式碼的時間複雜度為\(n^2\),有點慢,考慮優化
我們發現每次都在找最小值,那麼可以用一種資料結構維護最小值
STL很強大,有一種資料結構叫優先佇列,\(priority\) \(queue\)
可以維護最小值在頂部
模板題目
程式碼實現:

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
const int INF = INT_MAX;
typedef pair <int, int> PII;
#define mp make_pair
int n, m, s, u, v, w, d[MAXN];
vector <PII> G[MAXN];
bool vis[MAXN];
priority_queue <PII> q; //在頂部的是最大值
// priority_queue <PII, vector <PII>, greater <PII> >可以維護最小值,但效率對變低
void dijkstra() {
	q.push(mp(0, s));
	while (!q.empty()) {
		int x = q.top().second; q.pop();
		if (vis[x]) continue;
		vis[x] = 1;
		for (int i = 0; i < G[x].size(); ++i) {
			int t2 = G[x][i].second, t1 = G[x][i].first;
			if (d[t2] > d[x] + t1) {
				d[t2] = d[x] + t1;
				q.push(mp(d[t2], t2));
			}
		}
	}
}
int main() {
//	q.push(mp(5, 4)), q.push(mp(5, 3));
//	while (!q.empty()) cout << q.top().first << " " << q.top().second << endl, q.pop();
	scanf("%d%d%d", &n, &m, &s);
	for (int i = 1; i <= m; ++i) 
		scanf("%d%d%d", &u, &v, &w), G[u].push_back(mp(w, v));
	for (int i = 1; i <= n; ++i) d[i] = INF;
	d[s] = 0;
	dijkstra();
	for (int i = 1; i <= n; ++i) printf("%d ", d[i]); 
	return 0;
}