原题链接:
跑路 - 洛谷
解题思路:
如果u到v之间有一条长度为2^t的路径,那就把dis[u][v]改为1,所以我们先结合倍增法跑一遍floyd,得到新图,然后在新图上再跑一次最短路,这次可以用任何的最短路算法,但我们还是选择最简单最好写的floyd。
代码(CPP):
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 55;
const int INF = 0x3fffffff;
const int mod = 1000000007;
bool p[maxn][maxn][maxn]; // p[u][v][t] = true表示u、v之间有一条长度为2^t的路径
int dis[maxn][maxn];void solve() {fill(dis[0], dis[0] + maxn * maxn, INF);int n, m;cin >> n >> m;for (int i = 1; i <= m; i++) {int u, v;cin >> u >> v;dis[u][v] = 1;p[u][v][0] = true;}// 利用倍增原理计算新图。根据floyd的思路,路径通过一个中转点k,有p[i][j][t] = p[j][k][t - 1] + p[k][j][t - 1]for (int t = 1; t <= 32; t++) { // 长度为2^t的路径for (int k = 1; k <= n; k++) { // floydfor (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {if (p[i][k][t - 1] == true && p[k][j][t - 1] == true) {p[i][j][t] = true;dis[i][j] = 1;}}}}}// 在新图上用floyd求最短路径for (int k = 1; k <= n; k++) {for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {if (dis[i][k] != INF && dis[k][j] != INF && dis[i][k] + dis[k][j] < dis[i][j]) {dis[i][j] = dis[i][k] + dis[k][j];}}}}cout << dis[1][n] << endl;
}int main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cout << fixed;cout.precision(18);solve();return 0;
}