P2886 [USACO07NOV]Cow Relays G
天天刷水题,结果都做不出来
思路
我们定义 \(f_{i,u,v}\) 表示从 \(u\) 到 \(v\) ,恰好经过 \(i\) 条边的最短路
我们可以思考这样的一个转移:
\[f_{i,u,v}=\min\{f_{a,u,k}+f_{b,k,v}\}\ (a+b=i)
\]
这个样子是不是像极了两个矩阵,矩阵上 \(a_{i,j}\) 表示 \(i\) 到 \(j\) 走过 \(k\) 条边的最短路,然后将这两个矩阵进行 min乘
其实,我们可以将它看成一条一条边扩展,因此转移也可以这样写:
\[f_{i,u,v}=\min\{f_{i-1, u, k}+f_{1,k,v}\}
\]
也就是每次乘上一个“单位矩阵”,这就可以用矩阵快速幂来处理
代码
#include<iostream>
#include<fstream>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#define LL long long
#define FOR(i, x, y) for(int i = (x); i <= (y); i++)
#define ROF(i, x, y) for(int i = (x); i >= (y); i--)
#define PFOR(i, x) for(int i = he[x]; i; i = r[i].nxt)
inline int reads()
{
int sign = 1, re = 0; char c = getchar();
while(c < '0' || c > '9'){if(c == '-') sign = -1; c = getchar();}
while('0' <= c && c <= '9'){re = re * 10 + (c - '0'); c = getchar();}
return sign * re;
}
int n, t, s, e;
int id[1005], cnt;
struct Matrix
{
int a[105][105];
Matrix() {memset(a, 63, sizeof(a));}
inline int* operator [] (const int b) {return a[b];}
inline Matrix operator * (Matrix b)
{
Matrix re;
FOR(k, 1, cnt) FOR(i, 1, cnt) FOR(j, 1, cnt)
re[i][j] = std::min(re[i][j], a[i][k] + b[k][j]);
return re;
}
}ans;
inline Matrix qpow(Matrix a, int b)
{
Matrix re = a; b--;
while(b)
{
if(b & 1) re = re * a;
a = a * a;
b >>= 1;
}
return re;
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
#endif
n = reads(), t = reads(), s = reads(), e = reads();
id[s] = ++cnt, id[e] = ++cnt;
FOR(i, 1, t)
{
int w = reads(), u = reads(), v = reads();
if(!id[u]) id[u] = ++cnt;
if(!id[v]) id[v] = ++cnt;
ans[id[u]][id[v]] = ans[id[v]][id[u]] = std::min(ans[id[u]][id[v]], w);
}
ans = qpow(ans, n);
printf("%d", ans[id[s]][id[e]]);
return 0;
}