题目
算法标签: 倍增, 动态规划, 最短路
思路
题目给定 2 k 2 ^ k 2k步内都可以 1 1 1秒到达, 因此可以定义一个状态 f [ k ] [ i ] [ j ] f[k][i][j] f[k][i][j]表示是否存在一条长度为 2 k 2 ^ k 2k的路径使得 i i i能走到 j j j, 观察数据范围, 点的数量是 50 50 50, 可以直接枚举三个点, 计算出 f f f数组, 如果能到达将两个点直接距离标记为 1 1 1, 然后求最短路即可
代码
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
typedef unsigned long long ULL;
const int N = 60, M = 1e4 + 10, K = 65;
int n, m;
int f[K][N][N], d[N][N];
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n >> m;
memset(d, 0x3f, sizeof d);
for (int i = 1; i <= n; ++i) d[i][i] = 0;
for (int i = 0; i < m; ++i) {
int u, v;
cin >> u >> v;
d[u][v] = 1;
f[0][u][v] = 1;
}
for (int k = 1; k < K; ++k) {
for (int i = 1; i <= n; ++i) {
for (int t = 1; t <= n; ++t) {
for (int j = 1; j <= n; ++j) {
if (f[k - 1][i][t] && f[k - 1][t][j]) {
f[k][i][j] = 1;
d[i][j] = min(d[i][j], 1);
}
}
}
}
}
for (int k = 1; k <= n; ++k) {
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}
}
}
int ans = d[1][n];
cout << ans << "\n";
return 0;
}

京公网安备 11010502036488号