AcWing 牛站
Posted bigyellowdog
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AcWing 牛站相关的知识,希望对你有一定的参考价值。
AcWing 牛站
Description
给定一张由T条边构成的无向图,点的编号为1~1000之间的整数。
求从起点S到终点E恰好经过N条边(可以重复经过)的最短路。
Input
第1行:包含四个整数N,T,S,E。
第2..T+1行:每行包含三个整数,描述一条边的边长以及构成边的两个点的编号。
Output
- 输出一个整数,表示最短路的长度。
Sample Input
2 6 6 4 11 4 6 4 4 8 8 4 9 6 6 8 2 6 9 3 8 9
Sample Output
10
Data Size
10
题解:
- 矩阵快速幂。
- 挺妙的一道题。当我们设A(i, j)为i到j经过0条边的最短路。那么显然原图的邻接矩阵就是A矩阵,我们再设B(i, j)为i到j经过1条边的最短路。 那么我们只需要枚举中间点k,然后在A矩阵中进行松弛即可。那么A矩阵枚举一次中转点得到B矩阵。那么我要求经过N条道的矩阵。那么不就是A矩阵枚举N次中转点吗?即A矩阵的N次方次运算。但是,矩阵乘法中发生了变动,即变成了类似Floyd的东西,因为要求最短路。你可能会问,为什么快速幂又不用变呢?快速幂只是保证进行运算的次数。
- 那么枚举中转点后,如果更新呢?举个例子,假设现在有4个点1、2、3、4。现要更新2到1的最短路。我们可以看看dis(2, 1) + dis(1, 1)是否 < dis(1, 2);dis(2, 2) + dis(2, 1)是否 < dis(1, 2);dis(2, 3) + dis(3, 1)是否 < dis(1, 2);dis(2, 4) + dis(4, 1)是否 < dis(1, 2)。那么放在矩阵中看,刚好就是矩阵A和矩阵A进行运算的位置(2, 1)的结果。所以可以用矩阵乘法的运算法则去算,算的内容用松弛操作。
总结:进行N次运算,一次运算的定义是枚举中转点进行松弛操作,运算的实现用矩阵乘法的运算法则和Floyd的思想实现。
代码细节:原图时(i, i)不能置为0。因为我可以问你从1点到1点经过5条道路的最短路是多少(显然不是0
#include <iostream>
#include <cstdio>
#include <cstring>
#define N 205
using namespace std;
struct A
int m[N][N];
A() memset(m, 0x3f, sizeof(m));
a;
struct E int u, v, w; e[N];
int k, m, sta, en, n;
int b[N], f[1000005];
A mul(A x, A y)
A z;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
for(int k = 1; k <= n; k++)
z.m[i][j] = min(z.m[i][j], x.m[i][k] + y.m[k][j]);
return z;
A power(A a, int b)
A r = a, base = a;
while(b)
if(b & 1) r = mul(r, base);
base = mul(base, base);
b >>= 1;
return r;
int main()
cin >> k >> m >> sta >> en;
for(int i = 1; i <= m; i++)
cin >> e[i].w >> e[i].u >> e[i].v;
if(!f[e[i].u]) f[e[i].u] = ++n;
if(!f[e[i].v]) f[e[i].v] = ++n;
for(int i = 1; i <= m; i++)
int u = f[e[i].u], v = f[e[i].v];
a.m[u][v] = a.m[v][u] = min(a.m[v][u], e[i].w);
a = power(a, k - 1);
cout << a.m[f[sta]][f[en]];
return 0;
以上是关于AcWing 牛站的主要内容,如果未能解决你的问题,请参考以下文章