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;
}
-------------------------------------------------------
kedebug
Department of Computer Science and Engineering,
Shanghai Jiao Tong University
E-mail: kedebug0@gmail.com
GitHub: http://github.com/kedebug
-------------------------------------------------------