• Luogu 2886 [USACO07NOV]牛继电器Cow Relays


    BZOJ 1706权限题。

    倍增$floyd$。

    首先这道题有用的点最多只有$200$个,先离散化。

    设$f_{p, i, j}$表示经过$2^p$条边从$i$到$j$的最短路,那么有转移$f_{p, i, j} = min(f_{p - 1, i, k} + f_{p - 1, k, j})$。

    然后做一个类似于快速幂的东西把$n$二进制拆分然后把当前的$f$代进去转移。

    可以设一个$g_{i, j}$表示当前从$i$到$j$的最短路,为了保证转移顺序的正确,可以把$g$抄出来到$h$中,然后用$g_{i, j} = min(h_{i, k} + f_{p, k, j})$转移。

    时间复杂度$O(m^3logn)$。

    Code:

    #include <cstdio>
    #include <cstring>
    using namespace std;
    typedef long long ll;
    
    const int N = 205;
    const int M = 1e6 + 5;
    const int Lg = 22;
    
    int n, m, cnt = 0, id[M];
    ll f[Lg][N][N], g[N][N], h[N][N];
    
    template <typename T>
    inline void read(T &X) {
        X = 0; char ch = 0; T op = 1;
        for(; ch > '9' || ch < '0'; ch = getchar())
            if(ch == '-') op = -1;
        for(; ch >= '0' && ch <= '9'; ch = getchar())
            X = (X << 3) + (X << 1) + ch - 48;
        X *= op;
    }
    
    inline int getId(int now) {
        if(!id[now]) id[now] = ++cnt;
        return id[now];
    }
    
    template <typename T>
    inline void chkMin(T &x, T y) {
        if(y < x) x = y;
    }
    
    inline void mul(int p) {
        for(int i = 1; i <= cnt; i++)
            for(int j = 1; j <= cnt; j++)
                h[i][j] = g[i][j];
        
        memset(g, 0x3f, sizeof(g));    
        for(int k = 1; k <= cnt; k++)
            for(int i = 1; i <= cnt; i++)
                for(int j = 1; j <= cnt; j++)
                    chkMin(g[i][j], h[i][k] + f[p][k][j]);
    }
    
    int main() {
    //    freopen("2.in", "r", stdin);
        
        int st, ed;
        read(n), read(m), read(st), read(ed);
        st = getId(st), ed = getId(ed); 
        
        memset(f, 0x3f, sizeof(f));
        for(int i = 1; i <= m; i++) {
            int x, y; ll v;
            read(v), read(x), read(y);
            x = getId(x), y = getId(y); 
            chkMin(f[0][x][y], v), chkMin(f[0][y][x], v);    
        }
        
        for(int p = 1; p <= 20; p++)
            for(int k = 1; k <= cnt; k++)
                for(int i = 1; i <= cnt; i++)
                    for(int j = 1; j <= cnt; j++)
                        chkMin(f[p][i][j], f[p - 1][i][k] + f[p - 1][k][j]);
        
        memset(g, 0x3f, sizeof(g));
        for(int i = 1; i <= cnt; i++) g[i][i] = 0LL;
        for(int tmp = n, p = 0; tmp > 0; tmp >>= 1) {
            if(tmp & 1) mul(p);
            ++p;
        } 
        
        printf("%lld
    ", g[st][ed]);
        return 0;
    }
    View Code
  • 相关阅读:
    RequestMappin
    数组换位子
    mysql 数据表中查找重复记录(条数)
    post测试
    maven
    常用String练习
    删除重复数据
    推荐几个不错的jQuery图表插件,让你的报表更清晰动感
    纯CSS画的基本图形(矩形、圆形、三角形、多边形、爱心、八卦等),NB么?
    在中国,我们的知识产权真的陨落了吗?
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/9905088.html
Copyright © 2020-2023  润新知