洛谷题单指南-树与图上的动态规划-P1613 跑路
原题链接:https://www.luogu.com.cn/problem/P1613
题意解读:求从1到n的路径最少包含多少个2^k。
解题思路:
如果对于从所有点经过2^k的路径能到达的点,都标记为可达且距离为1
那么从1到n最少包含多少个2^k,就是一个求最短路径的问题,数据量不大,可以用Floyd算法
而对于标记两点是否可达,可以借助倍增ST表的思想:
设f[i][j][k]=1表示从i到j路径长度是2^k,那么对于所有的k,所有的中间节点t,有f[i][j][k] = f[i][t][k-1] && f[t][j][k-1]
同时设g[i][j]表示从i到j最少走几秒,在更新f时同步更新g,最后对g跑一遍Floyd即可。
100分代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 55;
bool f[N][N][64]; //f[i][j][k]=1表示从i到j路径长度是2^k
int g[N][N]; //g[i][j]表示从i到j最少走几秒
int n, m;
int main()
{
memset(g, 0x3f, sizeof(g));
cin >> n >> m;
while(m--)
{
int u, v;
cin >> u >> v;
f[u][v][0] = 1;
g[u][v] = 1;
}
//倍增预处理
for(int k = 1; k < 64; k++)
for(int t = 1; t <= n; t++)
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
if(f[i][t][k - 1] && f[t][j][k - 1])
f[i][j][k] = 1, g[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++)
g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
cout << g[1][n];
return 0;
}