zoukankan      html  css  js  c++  java
  • 灾后重建

    传送门

    这道题一开始的暴力做法就是直接模拟之后用dij跑最短路。其实它的极限值还没到1e8不过有常数你还是会超时。

    上面的暴力能得60分。

    之后我们考虑正解,因为数据范围是200所以我们可以直接跑Floyd。不过问题是我们怎么在一张不是完整的图上更新距离。

    Floyd算法的本质是动态规划,其转移方程 为:f[k][i][j] = min( f[k-1][i][j], f([k-1][i] [k])+f[k-1][k][j] )。

    f[k][i][j]表示路径除开起点i与终点j,只经过前k个点中的某些 点,从i到j的最小值。计算这个值只需要考虑两种情况:最短路经 过k,和最短路不经过k(那么就经过前k-1个点中的某些点)。由于 k要从k-1转移而来,自然k为最外层的循环。而经过滚动(类似于背 包问题)后,就变成了我们熟悉的f[i][j]=min(f[i][j],f[i] [k]+f[k][j])了。

    仔细思考之后发现……其实你每加入一个新的点,你所能更新的点对之间的距离一定是与这个点有关的……其实就是一个Floyd 的过程!把当前加入的这个点当做中间点k,枚举i,j就可以了。

    这样时间复杂度是On^3,可以过。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<queue>
    #include<set>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define pr pair<int,int>
    #define mp make_pair
    #define enter putchar('
    ')
    
    using namespace std;
    typedef long long ll;
    const int M = 50005;
    const int INF = 0x3fffffff;
    
    int read()
    {
        int ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
        if(ch == '-') op = -1;
        ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
        ans *= 10;
        ans += ch - '0';
        ch = getchar();
        }
        return ans * op;
    }
    
    struct edge
    {
        int next,to,v;
    }e[M<<1];
    
    int n,m,t[205],x,y,z,ecnt,head[205],qu,h = 0,dis[205][205],day[M],fr[M],st[M];
    bool pd[205];
    
    int main()
    {
        n = read(),m = read();
        rep(i,0,n-1)
        rep(j,0,n-1) if(i^j) dis[i][j] = INF;
        rep(i,0,n-1) t[i] = read();
        rep(i,1,m)
        {
        x = read(),y = read(),z = read();
        dis[x][y] = dis[y][x] = z;
        }
        qu = read();
        rep(i,1,qu)
        {
        x = read(),y = read(),z = read();
        while(t[h] <= z && h < n)
        {
            pd[h] = 1;
            rep(i,0,n-1)
            rep(j,0,n-1) dis[i][j] = min(dis[i][j],dis[i][h] + dis[h][j]);
            h++;
        }
        if(dis[x][y] == INF || !pd[x] || !pd[y]) printf("-1
    ");
        else printf("%d
    ",dis[x][y]);
        }
        return 0;
    }
  • 相关阅读:
    [算法练习]序列最大和
    [算法练习]最长公共子序列
    [算法练习]最长公共子串(LCS)
    [算法练习] 把字符串转换成整数
    [算法练习] 反转链表
    [算法练习] 正整数数制转换
    自己调用NTDLL函数
    [经典算法] 排列组合-N元素集合的所有子集(二)
    [经典算法] 排列组合-N元素集合的所有子集(一)
    【机器学习】主成分分析法 PCA (I)
  • 原文地址:https://www.cnblogs.com/captain1/p/9605534.html
Copyright © 2011-2022 走看看