zoukankan      html  css  js  c++  java
  • [USACO07NOV] Cow Relays

    传送门:>Here<

    题意:求在无向图中,S到E恰好经过T条边的最短路(边可重复走) ($T leq 100$)

    解题思路

    依然是好题。使用矩阵乘法——渐渐发现,矩阵乘法做图论题和Floyd有着很大的联系。从方程就能看出来相似:$f[i][k]+f[k][j]$和$f[i][k]*f[k][j]$。Floyd每次松弛一条边,最后拼凑出一条最短路。而邻接矩阵自乘k次相当于把自己松弛了k次——当然,和Floyd有所不同,Floyd如果无法松弛便不松弛,而矩阵乘法则会强行松弛k次,即使k次之后变成了0

    这道题和上一道题不同,不再是纯矩阵乘法,而是怎么说,修改了乘法的定义。依然看邻接矩阵,$g[i][j]$表示的是$i$到$j$经过一条边的最短路。因此当我们做矩阵乘法时,将$ sumlimits_{i=1}^{cnt} g[i][k]*g[k][j] $ 改为 $Min{ g[i][k]+g[k][j] }$,假设得到的矩阵为b,那么$b[i][j]$在$g$“自乘”一次以后得到的就是$i到j$恰好经过两条边的最短路。因此通过$g^k$就能够求出经过k条边的。其本质依然是矩阵乘法快速幂。只不过自乘变为了“自加”的形式

    Code

    注意不能够添加判断$if(i==j) continue$,因为即使起点终点相等,绕一圈回到自己也是一种走法(就因为这个调了一个小时……)

    另外,需要增加判断,转移时的$a[i][k]$与$a[k][j]$不能为0,因为我们需要保证严格的k条边。为0则代表那一部分不存在了……

    /*By DennyQi*/
    #include <cstdio>
    #include <queue>
    #include <cstring>
    #include <algorithm>
    #define  r  read()
    #define  Max(a,b)  (((a)>(b)) ? (a) : (b))
    #define  Min(a,b)  (((a)<(b)) ? (a) : (b))
    using namespace std;
    typedef long long ll;
    const int MAXN = 10010;
    const int MAXM = 27010;
    const int INF = 1061109567;
    inline int read(){
        int x = 0; int w = 1; register int c = getchar();
        while(c ^ '-' && (c < '0' || c > '9')) c = getchar();
        if(c == '-') w = -1, c = getchar();
        while(c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar(); return x * w;
    }
    int N,T,S,E,x,y,z,cnt;
    int g[105][105],ans[105][105],a[105][105],b[105][105],idx[1010];
    inline void Matrix_KSM(int y){
        while(y > 0){
            if(y & 1){
                for(int i = 1; i <= cnt; ++i){
                    for(int j = 1; j <= cnt; ++j){
                        b[i][j] = INF;
                        for(int k = 1; k <= cnt; ++k){
                            if(!ans[i][k] || !a[k][j]) continue;
                            b[i][j] = Min(b[i][j], ans[i][k] + a[k][j]);
                        }
                    }
                }
                for(int i = 1; i <= cnt; ++i){
                    for(int j = 1; j <= cnt; ++j){
                        ans[i][j] = b[i][j];
                    }
                }
            }
            for(int i = 1; i <= cnt; ++i){
                for(int j = 1; j <= cnt; ++j){
                    b[i][j] = INF;
                    for(int k = 1; k <= cnt; ++k){
                        if(!a[i][k] || !a[k][j]) continue;
                        b[i][j] = Min(b[i][j], a[i][k] + a[k][j]);
                    }
                }
            }
            for(int i = 1; i <= cnt; ++i){
                for(int j = 1; j <= cnt; ++j){
                    a[i][j] = b[i][j];
                }
            }
            y /= 2;
        }
    }
    int main(){
        N = r, T = r, S = r, E = r;
        memset(g, 0x3f, sizeof(g));
        for(int i = 1; i <= T; ++i){
            z = r, x = r, y = r;
            if(!idx[x]) idx[x] = ++cnt;
            if(!idx[y]) idx[y] = ++cnt;
            g[idx[x]][idx[y]] = Min(g[idx[x]][idx[y]],z);
            g[idx[y]][idx[x]] = Min(g[idx[y]][idx[x]],z);
        }
        for(int i = 1; i <= cnt; ++i){
            for(int j = 1; j <= cnt; ++j){
                a[i][j] = g[i][j];
                ans[i][j] = g[i][j];
            }
        }
        Matrix_KSM(N-1);
        printf("%d", ans[idx[S]][idx[E]]);
        return 0;
    }
  • 相关阅读:
    【Java】基本类型和引用类型(值传递)
    Linux学习笔记:什么是x86
    Java volatile keyword
    C语言可变參实现參数累加返回
    [Network]Application Layer
    linux下select,poll,epoll的使用与重点分析
    卷积神经网络(CNN)基础介绍
    ScrollView嵌套ExpandableListView显示不正常的问题
    【leetcode】 Unique Binary Search Trees II (middle)☆
    【leetcode】 Unique Binary Search Trees (middle)☆
  • 原文地址:https://www.cnblogs.com/qixingzhi/p/9439432.html
Copyright © 2011-2022 走看看