Poj 3613 Cow Relays (图论)

时间:2024-03-20 23:07:13

Poj 3613 Cow Relays (图论)

题目大意

给出一个无向图,T条边,给出N,S,E,求S到E经过N条边的最短路径长度

理论上讲就是给了有n条边限制的最短路

solution

最一开始想到是的去直接统计最短路经过了多少条边,结果,,,

还是太年轻了。。。

不过,看数据范围只有1000,那么floyd是首选

回顾Floyd算法流程,其中的i到j松弛操作是通过k完成的

那么松弛一次就利用一个k点,我现在要经过n条边,那么松弛n次即可

详细说就是更新一次之后,把f[i][j]拷贝到原来的a[i][j]中,然后再松弛,此时i、j之间就已经松弛了两次了

以此类推,利用矩阵快速幂优化

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
// #define int long long
using namespace std; inline int read(){
int x = 0, w = 1;
char ch = getchar();
for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') w = -1;
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
return x * w;
} int s, t, n, e;
int tot;
const int maxn = 555;
struct node{
int a[maxn][maxn];
node operator * (const node &x) const {
node b;
memset(b.a, 0x3f3f3f3f, sizeof b.a);
for(int k = 1; k <= tot; k++)
for(int i = 1; i <= tot ;i++)
for(int j = 1; j <= tot ;j++)
b.a[i][j] = min(b.a[i][j], a[i][k] + x.a[k][j]);
return b;
}
}ans, dis; int num[1000086];
signed main(){
memset(dis.a, 0x3f3f3f3f, sizeof dis.a);
n = read(), t = read(), s = read(), e = read();
while(t--){
int u = read(), v = read(), w = read();
if(!num[v]) num[v] = ++tot;
if(!num[w]) num[w] = ++tot;
dis.a[num[v]][num[w]] = dis.a[num[w]][num[v]] = u;
}
n--;
ans = dis;
while(n){
if(n & 1) ans = ans * dis;
dis = dis * dis;
n >>= 1;
}
cout << ans.a[num[s]][num[e]] << endl;
return 0;
}