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;
}
posted @ 2013-04-28 14:00  kedebug  阅读(405)  评论(0编辑  收藏  举报