题目链接:https://www.luogu.com.cn/problem/P1613
本题有一个跑路器,可以在一秒钟跑 2^k 千米。很显然,我们要将所有相距 2^k 千米的路径改为 1 秒钟可达。然后用Floyd跑最短路即可。要用什么方法呢,很明显要用倍增。记一个布尔型vis[i][j][k]数组,真的话表示 i~j 有一条 2^k 千米的路径。如果vis[i][t][k-1]为真,vis[t][j][k-1]为真,那么 i~j 就有一条 2^k 千米的路径,vis[i][j][k]标记为真。最后跑一下最短路就 OK 啦。
代码如下
#include <bits/stdc++.h>
using namespace std;
bool vis[52][52][65];//标记是否有2^k的路径
int dis[52][52];//点到点的距离
int n,m,u,v;
void floyd()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
if(dis[j][k]>dis[j][i]+dis[i][k])
dis[j][k]=dis[j][i]+dis[i][k];
}
int main()
{
scanf("%d %d",&n,&m);
memset(dis,10,sizeof(dis));
for(int i=1;i<=m;i++)
{
scanf("%d %d",&u,&v);
dis[u][v]=1;
vis[u][v][0]=1;//u到v有一条2^0的路径
}
for(int k=1;k<=64;k++)
for(int i=1;i<=n;i++)
for(int t=1;t<=n;t++)
for(int j=1;j<=n;j++)
{
//i~t有一条2^(k-1)的路,t~j有一条2^(k-1)
//所以i~j有一条2^k的路
if(vis[i][t][k-1]&&vis[t][j][k-1])
vis[i][j][k]=1,dis[i][j]=1;
}
floyd();
printf("%d\n",dis[1][n]);
return 0;
}