POJ 3613 Cow Relays(Floyd + 矩阵运算)

题意:

求 s 到 e 且经过 n 条边的最短路径。

思路:

1. Floyd 算法在维基百科上面有详细的介绍:https://zh.wikipedia.org/zh-cn/%E5%BC%97%E6%B4%9B%E4%BC%8A%E5%BE%B7%E7%AE%97%E6%B3%95

2. O(n3) 的算法一次性把结果求到位了,而不知道中间经历了多少边。而本题矩阵的解法则是“放慢”了的 floyd

3. Floyd 算法相当于利用二维的空间解决三维的问题,这点和 01 背包差不多。而代码中的每次矩阵相乘,实际上只是要多找一个边

4. 这里的单位矩阵 M2 也是和 E 有点出入的,具体就看代码吧。

 

#include <iostream>

#include <algorithm>

#include <map>

using namespace std;



const int MAXN = 210;



class Matrix {

public:

    int e[MAXN][MAXN], n;



    void setn(int n) { this->n = n; }

    void initvalue() { memset(e, 0x3F, sizeof(e)); }



    Matrix operator = (const Matrix& o) {

        for (int i = 1; i <= n; i++)

            for (int j = 1; j <= n; j++) 

                e[i][j] = o.e[i][j];

        return *this;

    }

    Matrix operator * (const Matrix& o) {

        Matrix m;

        m.initvalue();

        for (int k = 1; k <= n; k++)

            for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++)

                m.e[i][j] = min(m.e[i][j], e[i][k] + o.e[k][j]);

        return m;

    }

};



Matrix M1, M2;

map<int, int> my;



int main() {

    int n, t, s, e;

    while (~scanf("%d%d%d%d", &n, &t, &s, &e)) {

        int cflag = 0;

        M1.initvalue(); 

        M2.initvalue();

        for (int i = 0; i < t; i++) {

            int cost, u, v;

            scanf("%d%d%d", &cost, &u, &v);

            if (!my[u]) my[u] = ++cflag;

            if (!my[v]) my[v] = ++cflag;

            int a = my[u], b = my[v];

            M1.e[a][b] = M1.e[b][a] = cost;

        }

        for (int i = 1; i <= cflag; i++)

            M2.e[i][i] = 0;



        M1.setn(cflag), M2.setn(cflag);



        while (n) {

            if (n & 1)

                M2 = M1 * M2;

            M1 = M1 * M1;

            n >>= 1;

        }



        printf("%d\n", M2.e[my[s]][my[e]]);

    }

    return 0;

}

你可能感兴趣的:(floyd)