【luogu P1613】跑路

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;
}
原文地址:https://www.cnblogs.com/ssttkkl/p/7531659.html