LUOGU P1613 跑路 (倍增floyd)

解题思路

倍增$floyd$,首先设$f[i][j][k]$表示$i$这个点到$j$的距离能否为$2^k$,初值是如果x,y之间有边,那么$f[x][y][0]=1$。转移方程就是$f[i][j][t]|=(f[i][k][t-1]&f[k][j][t-1])$,就是传递闭包。因为跑步机只能到$2^k$,那么就把所有$f[i][j][k]=1$的(i,j)之间连一条距离为1的边,最后跑一个最短路。

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;
const int MAXN = 55;

inline int rd(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();}
    while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return f?x:-x;
}

int dis[MAXN][MAXN],n,m;
bool f[MAXN][MAXN][66];

int main(){
    memset(dis,0x3f,sizeof(dis));
    n=rd(),m=rd();int x,y;
    for(int i=1;i<=m;i++){
        x=rd(),y=rd();f[x][y][0]=1;
        dis[x][y]=1;if(x==y) {putchar('1');return 0;}
    }
    for(int t=1;t<=64;t++)
        for(int k=1;k<=n;k++)
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    if(f[i][k][t-1] && f[k][j][t-1]){
                        f[i][j][t]=1;
                        dis[i][j]=1;    
                    }
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
    cout<<dis[1][n];
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/sdfzsyq/p/9762316.html