1. 程式人生 > >Luogu1613 跑路-倍增+Floyd

Luogu1613 跑路-倍增+Floyd

++i spa $2 etc div str ons amp main

Solution

挺有趣的一道題, 仔細想想才想出來

先用$mp[i][j][dis]$ 是否存在一條 $i$ 到 $j$ 的長度為 $2^{dis}$ 的路徑。

轉移 :

1 for (int dis = 1; dis < base; ++dis)
2         for (int k = 1; k <= n; ++k)
3             for (int i = 1; i <= n; ++i) if (mp[i][k][dis - 1])
4                 for (int j = 1; j <= n; ++j) if
(mp[k][j][dis - 1]) 5 mp[i][j][dis] = 1;

若$mp[i][j][dis] = 1$, 則把 $f[i][j]$ 記為$1$

然後再用$f[i][j]$ 去跑$Floyd$。 這樣找出的路徑 一定是最短的(因為能合成 $2^dis$ 的路徑都已經被記錄了

Code

技術分享圖片
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define rd read()
 5 using
namespace std; 6 7 const int N = 55; 8 const int base = 32; 9 10 int mp[N][N][N], f[N][N]; 11 int n, m; 12 13 int read() { 14 int X = 0, p = 1; char c = getchar(); 15 for (; c > 9 || c < 0; c = getchar()) 16 if (c == -) p = -1; 17 for (; c >= 0 && c <=
9; c = getchar()) 18 X = X * 10 + c - 0; 19 return X * p; 20 } 21 22 void cmin(int &A, int B) { 23 if (A > B) A = B; 24 } 25 26 int main() 27 { 28 n = rd; m = rd; 29 memset(f, 63, sizeof(f)); 30 for (int i = 1; i <= m; ++i) { 31 int u = rd, v = rd; 32 mp[u][v][0] = 1; 33 } 34 for (int dis = 1; dis < base; ++dis) 35 for (int k = 1; k <= n; ++k) 36 for (int i = 1; i <= n; ++i) if (mp[i][k][dis - 1]) 37 for (int j = 1; j <= n; ++j) if (mp[k][j][dis - 1]) 38 mp[i][j][dis] = 1; 39 for (int dis = 0; dis < base; ++dis) 40 for (int i = 1; i <= n; ++i) 41 for (int j = 1; j <= n; ++j) if (mp[i][j][dis]) 42 f[i][j] = 1; 43 for (int k = 1; k <= n; ++k) 44 for (int i = 1; i <= n; ++i) 45 for (int j = 1; j <= n; ++j) 46 cmin(f[i][j], f[i][k] + f[k][j]); 47 printf("%d\n", f[1][n]); 48 }
View Code

Luogu1613 跑路-倍增+Floyd