Catalog
题解 P2886 【[USACO07NOV]牛继电器Cow Relays】

查看原题请戳这里

首先,我们要明确这里的最短路是在经过n条路径的前提下的最短路,因为这是无向图,所以一定有解。

我们先来看朴素的Floyd的代码:

1
2
3
4
for(int k = 1; k <= n; k++)
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
f[i][j] = min(f[i][j],f[i][k] + f[k][j]);

其中,我们每次都是枚举k并用ta去当中转点去更新每一个i->j的最短路。

那么,当k等于n/2时这段代码完成了什么呢?

那就是我们尝试了用[1,n/2]的点去更新最短路,我们可以发现,这样得到的最短路最多包含k+1条路径。

为什么是最多k+1条呢?

因为我们每次用k去尝试更新i->j的最短路是不一定成功(即f[i][j]<=f[i][k]+f[k][j])

所以我们可以用Floyd+dp+倍增去切掉这道题

我们再来看一下矩阵乘法的代码:

1
2
3
4
for(int k = 1; k <= n; k++)
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
c[i][j] = c[i][j] + a[i][k] * b[k][j];

是不是和Floyd的代码有点相似?

因为我们要求的是最短路,所以我们要对这个矩阵乘法魔改一下:

1
2
3
4
5
memset(c,0x7f,sizeof(c));
for(int k = 1; k <= n; k++)
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
c[i][j] = min(c[i][j],a[i][k] + a[k][j]);

是不是和Floyd越来越相似了……

但是在这里,c[i][j]的初值为INF,所以我们每次枚举k都会选择一条边去更新最短路,所以如果我们用邻接矩阵map(不是STL的那个map)去存边,那么map的n次方存的就是经过n条边的最短路。

code:

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define ll long long
#define INF 0x7fffffff
#define re register
#define rep(i,a,b) for(int i = (a); i <= (b); i++)
#define qwq printf("qwq\n");

using namespace std;

long long read()
{
register long long x = 0,f = 1;register char ch;
ch = getchar();
while(ch > '9' || ch < '0'){if(ch == '-') f = -f;ch = getchar();}
while(ch <= '9' && ch >= '0'){x = x * 10 + ch - 48;ch = getchar();}
return x * f;
}


long long n,m,t,sta,End,cnt,siz,u,d[100005];

struct edge{
int fro,to,l;
}e[100005];

struct juzhen{
long long a[105][105];
juzhen operator * (const juzhen &x) const
{
juzhen c;
memset(c.a,0x7f,sizeof(c.a));
for(int k = 1; k <= siz; k++)
for(int i = 1; i <= siz; i++)
for(int j = 1; j <= siz; j++)
c.a[i][j] = min(c.a[i][j],a[i][k]+x.a[k][j]);
return c;
}
}ans,map;

void ksm(int b)
{
while(b > 0)
{
if(b & 1) ans = ans * map;
map = map * map;
b >>= 1;
}
}

bool cmp(int a,int b){return a < b;}

int main()
{
n = read(); m = read(); sta = read(); End = read();
for(int i = 1; i <= m; i++)
{
e[i].l = read(); e[i].fro = read(); e[i].to = read();
d[++cnt] = e[i].fro; d[++cnt] = e[i].to;
}
sort(d + 1, d + cnt + 1, cmp);
siz = unique(d + 1, d + cnt + 1) - d - 1;
for(int i = 1; i <= siz; i++)
for(int j = 1; j <= siz; j++)
map.a[i][j] = INF;
for(int i = 1; i <= m; i++)
{
e[i].fro = lower_bound(d + 1, d + siz + 1, e[i].fro) - d;
e[i].to = lower_bound(d + 1, d + siz + 1, e[i].to) - d;
map.a[e[i].fro][e[i].to] = e[i].l;
map.a[e[i].to][e[i].fro] = e[i].l;
}
sta = lower_bound(d + 1, d + siz + 1, sta) - d;
End = lower_bound(d + 1, d + siz + 1, End) - d;// li san hua
for(int i = 1; i <= siz; i++)
for(int j = 1; j <= siz; j++)
ans.a[i][j] = map.a[i][j];
ksm(n - 1);
printf("%d\n",ans.a[sta][End]);
return 0;
}
Author: wflight
Link: http://yoursite.com/2019/10/19/题解-P2886-【-USACO07NOV-牛继电器Cow-Relays】/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
  • 支付寶

Comment