洛谷P1613 跑路 最短路+倍增

题目链接: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;
}

猜你喜欢

转载自blog.csdn.net/weixin_44491423/article/details/104542922