洛谷

洛谷题单指南-树与图上的动态规划-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;
}