zoukankan      html  css  js  c++  java
  • Luogu 1613 跑路(最短路径,倍增)

    Luogu 1613 跑路(最短路径,倍增)

    Description

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

    Input

    第一行两个整数n,m,表示点的个数和边的个数。

    接下来m行每行两个数字u,v,表示一条u到v的边。

    Output

    一行一个数字,表示到公司的最少秒数。

    Sample Input

    4 4
    1 1
    1 2
    2 3
    3 4

    Sample Output

    Http

    Luogu:https://www.luogu.org/problem/show?pid=1613

    Source

    最短路径,倍增

    解决思路

    这道题目是最短路径与倍增算法的综合运用。
    我们知道Floyed求最短路径的原理是用一个点k来修改i到j的最短距离。在这道题中,我们要灵活地用到这个方法。
    因为本题中小A每秒可以跑2^k(k为任意数),所以直接求最短路径是不对的。我们可以与处理出小A1秒钟可以到达的边,这个用Floyed实现,再用一个Floyde或spfa求出1到n的最短路径就可以了。

    那么关键就是如何进行预处理呢?
    我们可以用一个数组F来记录,F[i][u][v]表示u到v能否通过2^i到达,这也就是1秒。在读入的时候我们就可以得出F[0][u][v]的值,然后从1~32(因为maxlongint就是2^31)枚举i,同时枚举u和v,借助Floyed用第三个点来修改的这种思想,我们再枚举一个点k,若F[i-1][u][k]和F[i-1][k][v]同时为真,则说明F[i][u][v]为真(因为2^(i-1)+2^(i-1)=2*i)。这样我们就可以与处理出所有1秒可以到的边。

    然后再跑一边最短路就可以了。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int maxN=60;
    const int inf=2147483647;
    
    int n,m;
    int G[maxN][maxN];
    bool F[40][maxN][maxN];
    
    int main()
    {
        memset(G,120,sizeof(G));
        memset(F,0,sizeof(F));
        cin>>n>>m;
        for (int i=1;i<=m;i++)
        {
            int u,v;
            cin>>u>>v;
            G[u][v]=1;
            F[0][u][v]=1;//读入的同时给F赋初值
        }
        for (int i=1;i<=36;i++)//计算F,预处理
            for (int u=1;u<=n;u++)
                for (int v=1;v<=n;v++)
                    for (int k=1;k<=n;k++)
                            if ((F[i-1][u][k]==1)&&(F[i-1][k][v]==1))
                            {
                                F[i][u][v]=1;
                                G[u][v]=1;
                            }
        for (int i=1;i<=n;i++)//再用最短路求出1~n的最短距离
            for (int j=1;j<=n;j++)
                    for (int k=1;k<=n;k++)
                        if (G[i][k]+G[k][j]>=0)
                            G[i][j]=min(G[i][j],G[i][k]+G[k][j]);
        cout<<G[1][n]<<endl;
        return 0;
    }
    
  • 相关阅读:
    洛谷 P1194 飞扬的小鸟 题解
    洛谷 P1197 星球大战 题解
    洛谷 P1879 玉米田Corn Fields 题解
    洛谷 P2796 Facer的程序 题解
    洛谷 P2398 GCD SUM 题解
    洛谷 P2051 中国象棋 题解
    洛谷 P1472 奶牛家谱 Cow Pedigrees 题解
    洛谷 P1004 方格取数 题解
    洛谷 P2331 最大子矩阵 题解
    洛谷 P1073 最优贸易 题解
  • 原文地址:https://www.cnblogs.com/SYCstudio/p/7210732.html
Copyright © 2011-2022 走看看