洛谷1613 跑路(倍增)(floyd)

版权声明:本文为博主原创文章,未经博主允许不得转载,除非先点了赞。 https://blog.csdn.net/A_Bright_CH/article/details/83540624

题目

小A的工作不仅繁琐,更有苛刻的规定,要求小A每天早上在6:00之前到达公司,否则这个月工资清零。可是小A偏偏又有赖床的坏毛病。于是为了保住自己的工资,小A买了一个十分牛B的空间跑路器,每秒钟可以跑2^k千米(k是任意自然数)。当然,这个机器是用longint存的,所以总跑路长度不能超过maxlongint千米。小A的家到公司的路可以看做一个有向图,小A家为点1,公司为点n,每条边长度均为一千米。小A想每天能醒地尽量晚,所以让你帮他算算,他最少需要几秒才能到公司。数据保证1到n至少有一条路径。

心路

做不出来真不应该啊,想得太复杂了,其实要是最根本的最短路想起会简单很多。

题解

倍增+floyd
设g[x][y][k]表示x->y是否有一条长度为2^k的路径。这个很好求出来吧。初始值g[x][y][0]=true。
只要把这个最最最基础的设出来,什么距离为2,3,4……都可以表示出来。
接下来floyd做一遍就好了,f[x][y]表示x到y的最短距离。
喜欢用spfa也可以,但是建边比较麻烦。既然是邻接矩阵,floyd当然是首选了。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=60;

int n,m;
bool g[MAXN][MAXN][70];
int d[MAXN][MAXN];

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        g[x][y][0]=true;
    }
    
    for(int k=1;k<=64;k++)
        for(int l=1;l<=n;l++)
            for(int x=1;x<=n;x++)
                for(int y=1;y<=n;y++) g[x][y][k]|=g[x][l][k-1]&g[l][y][k-1];
    memset(d,0x3f,sizeof(d));
    for(int x=1;x<=n;x++)
        for(int y=1;y<=n;y++)
            for(int k=0;k<=64;k++) if(g[x][y][k]) d[x][y]=1;
    
    for(int k=1;k<=n;k++)
        for(int x=1;x<=n;x++)
            for(int y=1;y<=n;y++) if(d[x][y]>d[x][k]+d[k][y]) d[x][y]=d[x][k]+d[k][y];
    printf("%d\n",d[1][n]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/A_Bright_CH/article/details/83540624