求在一張有\(m\)條邊無向連通圖中,點\(s\)到點\(t\)的通過\(k\)條邊的最短路(\(1 \leq m \leq 100\),\(1 \leq k \leq 10^6\))。ios
邊數\(m\)很小,顯然點數\(n\)也很小,不超過\(200\),咱們能夠先離散化處理。
咱們能夠獲得\(n\)個點之間的鄰接矩陣,其中矩陣中的\(a[i][j]\)就至關於點\(i\)到點\(j\)的通過\(1\)條邊的最短路。
此時咱們設\(dp[i][j][k']\)表示點\(i\)到點\(j\)的通過\(k'\)條邊的最短路,顯然有
\[dp[i][j][1] = a[i][j]\]
且
\[dp[i][j][k'] = \min \{ dp[i][l][k' - 1]+ dp[l][j][k' - 1] \}, k' > 1\]
顯然,樸素的dp複雜度爲\(O(kn^2)\)。
觀察這個過程,其實很像矩陣乘法,一樣的,咱們也能夠用矩陣快速冪來優化,這樣複雜度就降到$O(n^2 \log{k}) $了。優化
#include <iostream> #include <cstring> #include <algorithm> #define MAX_M (100 + 5) using namespace std; int K, m, s, t; int u[MAX_M], v[MAX_M]; long long w[MAX_M]; int tmp[MAX_M << 1]; int to[1000005], n; struct Matrix { long long mat[MAX_M][MAX_M]; Matrix() { memset(mat, 0x3f, sizeof mat); return; } friend Matrix operator * (Matrix a, Matrix b) { Matrix c; for(int i = 1; i <= n; ++i) { for(int j = 1; j <= n; ++j) { for(int k = 1; k <= n; ++k) { c.mat[i][j] = min(c.mat[i][j], a.mat[i][k] + b.mat[k][j]); } } } return c; } friend Matrix operator *= (Matrix & a, Matrix b) { return a = a * b; } }; Matrix a; int main() { cin >> K >> m >> s >> t; for(int i = 1; i <= m; ++i) { cin >> w[i] >> u[i] >> v[i]; tmp[i << 1 ^ 1] = u[i]; tmp[i << 1] = v[i]; } sort(tmp + 1, tmp + m + m + 1); for(int i = 1; i <= (m << 1); ++i) { if(tmp[i] != tmp[i - 1]) to[tmp[i]] = ++n; } for(int i = 1; i <= m; ++i) { u[i] = to[u[i]]; v[i] = to[v[i]]; a.mat[u[i]][v[i]] = min(a.mat[u[i]][v[i]], w[i]); a.mat[v[i]][u[i]] = min(a.mat[v[i]][u[i]], w[i]); } --K; Matrix res = a; while(K) { if(K & 1) res *= a; a *= a; K >>= 1; } cout << res.mat[to[s]][to[t]]; return 0; }