• 洛谷1613 跑路 倍增 + Floyd


    首先,我们一定要认识到本题中的最短时间所对应的道路不一定是在起点到终点的最短路。例如,起点到终点的最短路为 1515 ,那么对 1515 进行二进制拆分的话是 11111111 ,这时求出的最短时间为4。然而如果有一条长度为 1616 的路径的话最短时间就为 11,显然比之前求的更优 。
    我们在这里定义两个数组:

    1. intint d[i][j]d[i][j],即代表点 (i,j)(i,j) 之间的最短跑步时间。
    2. boolbool g[i][j][k]g[i][j][k],它代表的是点 (i,j)(i,j) 之间是否有一条跑步时间为 2k2^k 的一条道路。
      我们对 g[i][j][k]g[i][j][k] 运行一遍 FloydFloyd 来更新。
      更新方程是:
      if(g[i][k][log1]if(g[i][k][log-1] && g[k][j][log1])g[k][j][log-1]) g[i][j][log]=1g[i][j][log]=1d[i][j]=1d[i][j]=1.

    显然,我们处理完 gg 数组后所有可以在一秒之内到达的点对都已处理完毕。于是我们在图上对 d[i][j]d[i][j] 再跑一遍 FloydFloyd 即可。
    时间复杂度为 O(n3logm)O(n^3logm)

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int logn = 60;
    const int maxm = 500000 + 5;
    const int maxn = 60;
    const int inf  = 100000000;
    int d[maxn][maxn];
    bool g[maxn][maxn][logn];
    int main()
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i = 1; i <= n;++i)
           for(int j = 1;j <= n;++j)d[i][j] = inf;
        for(int i = 1;i <= m;++i)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            d[a][b] = 1, g[a][b][0] = 1;
        }
        for(int p = 1; p < logn; ++p)
            for(int k = 1; k <= n;++k)
                for(int i = 1; i <= n; ++i)
                    for(int j = 1; j <= n;++j)
                    {
                        if(g[i][k][p-1] && g[k][j][p-1]) g[i][j][p] = 1, d[i][j] = 1;
                    }
        for(int k = 1;k <= n;++k)
            for(int i = 1;i <= n;++i)
                for(int j = 1;j <= n;++j)
                    d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
        printf("%d",d[1][n]);
        return 0;
    }
    
  • 相关阅读:
    tuple 元组及字典dict
    day 49 css属性补充浮动 属性定位 抽屉作业
    day48 选择器(基本、层级 、属性) css属性
    day47 列表 表单 css初识
    day 46 http和html
    day 45索引
    day 44 练习题讲解 多表查询
    day 40 多表查询 子查询
    day39 表之间的关联关系、 补充 表操作总结 where 、group by、
    day38 数据类型 约束条件
  • 原文地址:https://www.cnblogs.com/guangheli/p/9845116.html
Copyright © 2020-2023  润新知