洛谷P2886【USACO07NOV】Cow_Relays

题目

题解

  • 看到这个边的数量,一下子→Floyd。
  • 那么对于Floyd,每次加入一个点扩展是不是就多了一条边呢?所以会想到扩展k次点来得到最短路。但是k很大,那么考虑一下,对于一个图的邻接矩阵G而言(初始连通1,不连通0)一开始的读入后得到的G就是表示两点是否直接可达。
  • 每一次选择中间扩展点k的时候,[i,k]+[k,j]是不是很眼熟?Floyd的过程实际上是类似于矩阵乘法的,只不过要求松弛而已。使用矩乘,就可以模拟扩展点的时候计算此时经过了n条边的最短路径长度。
  • 一次Floyd后所求的矩阵就是在(i,j)中插入一个点的k。那么不断插入,就能一直推下去推到经过k条边的最短路。要注意每次都使用新的数组,用以前的数组进行更新,才能保证,每次只用到了一个点来更新。
  • 对于这题思想拓展推荐大家可以去看一下国家队论文《矩阵乘法在信息学中的应用》,十分实用。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include<bits/stdc++.h>
#define RG register
#define file(x) freopen(#x".in", "r", stdin);freopen(#x".out", "w", stdout);
#define clear(x, y) memset(x, y, sizeof(x));
using namespace std;

template<typename T = int>
inline T read()
{
T data=0, w=1;
char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') w=-1, ch=getchar();
while(ch>='0'&&ch<='9') data=(data<<3)+(data<<1)+(ch^48), ch=getchar();
return data*w;
}

const int N(210);
typedef long long ll;
int k, t, s, e, cnt, pos[2010];
class Matrix
{
private:
ll a[N][N];
public:
Matrix() { clear(a, 0x3f); }
ll *operator [] (int index) { return a[index]; }
Matrix operator * (Matrix &b)
{
Matrix c;
for(RG int k=1;k<=cnt;k++)
for(RG int i=1;i<=cnt;i++)
for(RG int j=1;j<=cnt;j++)
c[i][j]=min(c[i][j], a[i][k]+b[k][j]);
return c;
}
}G, A;

ll x, y, z;
int main()
{
k=read(); t=read(); s=read(); e=read();
for(RG int i=1;i<=t;i++)
{
z=read(); x=read(); y=read();
if(!pos[x]) pos[x]=++cnt;
if(!pos[y]) pos[y]=++cnt;
G[pos[x]][pos[y]]=G[pos[y]][pos[x]]=min(G[pos[x]][pos[y]], z);
}
for(RG int i=1;i<=cnt;i++) A[i][i]=0;
while(k)
{
if(k&1) A=A*G;
G=G*G;
k>>=1;
}
printf("%lld\n", A[pos[s]][pos[e]]);
return 0;
}
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×