题意:小A的工作不仅繁琐,更有苛刻的规定,要求小A每天早上在\(6:00\)之前到达公司,否则这个月工资清零.可是小A偏偏又有赖床的坏毛病。于是为了保住自己的工资,小A买了一个十分牛B的空间跑路器,每秒钟可以跑\(2^k\)千米(\(k\)是任意自然数).当然,这个机器是用\(longint\)存的,所以总跑路长度不能超过\(max_{longint}\)千米.小A的家到公司的路可以看做一个有向图,小A家为点1,公司为点n,每条边长度均为一千米.小A想每天能醒地尽量晚,所以让你帮他算算,他最少需要几秒才能到公司.数据保证1到n至少有一条路径.\(n<=50,m<=10000\)
分析:倍增\(Floyd\).设\(dis[i][j]\)表示i到j最少需要几秒,\(f[i][j][p]\)表示i到j的距离是否是\(2^p\)千米.
\(f[i][j][p]|=f[i][k][p-1]\)&\(f[k][j][p-1]\),当\(f[i][j][p]\)为1时,\(dis[i][j]=1.\)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
int x=0,o=1;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')o=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*o;
}
const int N=55;
int dis[N][N],f[N][N][N];
int main(){
memset(dis,0x3f,sizeof(dis));//初始化无穷大
int n=read(),m=read();
for(int i=1;i<=m;++i){
int a=read(),b=read();
dis[a][b]=1;f[a][b][0]=1;//初始化
}
for(int p=1;p<=30;++p)
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][p-1]&&f[k][j][p-1]){//同时更新
dis[i][j]=1;
f[i][j][p]=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]);
printf("%d\n",dis[1][n]);
return 0;
}