跑路

洛咕

题意:小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<=10;++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
",dis[1][n]);
    return 0;
}

原文地址:https://www.cnblogs.com/PPXppx/p/11613008.html