https://www.luogu.org/problem/show?pid=1613
看到2k就能想到倍增。用一个数组avai[i][j][k]表示点i与点j是否存在长2k的路径,则可以递推出avai[i][j][k]=any{avai[i][v][k-1]&avai[v][j][k-1]},初始值avai[i][i][0]=true。如果avai[i][j][k]==true,则在i点与j点加一条长1的路径。最后BFS或者直接Floyd跑一遍最短路径就可以了。
#include <iostream> #include <vector> #include <queue> #include <cstring> #define maxn 55 using namespace std; int n, m; int g[maxn][maxn]; bool avai[maxn][maxn][65]; int main() { ios::sync_with_stdio(false); memset(g, 0x3f, sizeof(g)); cin >> n >> m; int u, v; for (int i = 1; i <= m; i++) { cin >> u >> v; avai[u][v][0] = g[u][v] = 1; } for (int i = 1; i <= n; i++) g[i][i] = 1; //f(i,j,k)=f(i,v,k-1)&&f(v,j,k-1) for (int k = 1; k <= 64; k++) { for (int u = 1; u <= n; u++) { for (int v = 1; v <= n; v++) { for (int w = 1; w <= n; w++) { if (avai[u][v][k] |= avai[u][w][k - 1] == 1 && avai[w][v][k - 1] == 1) g[u][v] = 1; } } } } for (int k = 1; k <= n; k++) for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) g[i][j] = min(g[i][k] + g[k][j], g[i][j]); cout << g[1][n] << endl; return 0; }