1. 程式人生 > >關於dijkstra的小根堆優化

關於dijkstra的小根堆優化

eat algo 最壞情況 str 但是 lan 部分 是我 算法

YY引言

在NOI2018D1T1中出現了一些很震驚的情況,D1T1可以用最短路解決,但是大部分人都在用熟知的SPFA求解最短路。而SPFA的最壞復雜度能夠被卡到$O(VE)$。就是邊的數量乘以點的數量,而用SPFA的各位都被惡意數據卡成了最壞情況。100->60。這顯然很不劃算。是時候祭出我們的堆優化$dijkstra$了。

核心思想

樸素的dijkstra的核心是一個貪心的過程。每次找當前已知權值的最小的邊來進行松弛。但是每次找的過程中都要用$O(m)$的時間。這樣很慢。時間復雜度是$O((m+n)n)$。這顯然不是我們想要的結果。小根堆的特性是保證堆頂的數是最小的數,所以我們可以用小根堆來替換貪心找最小權值的過程。而使用了小根堆之後的$dijkstra$算法的時間復雜度就變成了$O((m+n)\log n)$,而且很穩定。

代碼實現

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

typedef pair<long long, int> P;
const int maxedge = 2e5+3;
const int maxnode = 1e5+3;
priority_queue<P, vector<P>, greater<P> > Q;
int fir[maxnode], nx[maxedge], u[maxedge], v[maxedge], w[maxedge];
int dis[maxnode], n, m, s;
bool book[maxnode];
inline int read() {
	int x = 0, f = 1; char c = getchar();
	while (c < ‘0‘ || c > ‘9‘) {if(c == ‘-‘) f = -1; c = getchar();}
	while (c <= ‘9‘ && c >= ‘0‘) {x = x*10 + c-‘0‘; c = getchar();}
	return x * f;
}

int main() {
	n = read(), m = read(), s = read();
	memset(fir, -1, sizeof(fir));
	fill(dis+1, dis+1+n, 2147483647);
	for(int i=1; i<=m; i++) {
		u[i] = read(), v[i] = read(), w[i] = read();
		nx[i] = fir[u[i]];
		fir[u[i]] = i;
	}
	dis[s] = 0;
	Q.push(P(0, s));
	while (!Q.empty()) {
		P x = Q.top();
		Q.pop();
		if(x.first > dis[x.second])
			continue;
		int k = fir[x.second];
		while (k != -1) {
			if(x.first + w[k] < dis[v[k]]) {
				dis[v[k]] = w[k] + x.first;
				Q.push(P(dis[v[k]], v[k]));
			}
			k = nx[k];
		}
	}
	for(int i=1; i<=n; i++) printf("%d ", dis[i]);
}

  

模板題目

Luogu P4779,這個題卡SPFA

Luogu P3371,這個題不卡SPFA

關於dijkstra的小根堆優化