第8讲 最小生成树、最短路、关键路径

1.最小生成树 MST

无向图

不一定唯一

唯一条件: 任意环中边权都不同

(1) Prim

朴素: $O(n^2)$ 稠密图

堆优化: $O(mlogn)$ 稀疏图 少用

AcWing 858. Prim算法求最小生成树

S:当前已经在联通块中的所有点的集合

  1. dist[i] = inf
  2. for n 次
    找到不在s集合中,距离s集合最近的点t
    将这个点t放入集合中
    利用这个点t, 更新不在集合中的点

联系:Dijkstra算法是更新到起始点的距离,Prim是更新到集合S的距离

Prim算法与Dijkstra算法的区别
Dijkstra算法是更新不在集合中的点 离起点的距离

dist[j]=min(dist[j], dist[t]+g[t][j])

Prim是更新不在集合中的点 离集合S的距离

dist[j] = min(dist[j], g[t][j])

c++:

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
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 505, INF = 0x3f3f3f3f;
int n,m;
int g[N][N], dist[N]; //dist存储其他点到S的距离
bool st[N];


int prim(){

memset(dist, 0x3f, sizeof dist);
dist[1]=0;
int res = 0;
for(int i=0;i<n;i++) // n个点
{
// 寻找离集合S最近的点
int t = -1 ;
for(int j = 1; j <=n ;j++)
if(!st[j] && ( t==-1 || dist[t]>dist[j] ) )
t = j ; // 更新t

// 当前可选的最短路径的点距离都是INF 说明不联通,return
if(dist[t] == INF ) return INF;

st[t]= true;

res += dist[t];
//利用这个点t, 更新不在集合中的点
for(int j = 1;j<=n;j++)
dist[j] = min(dist[j],g[t][j]);


}

return res;
}

int main()
{
cin>>n>>m;
memset(g,0x3f, sizeof g);
while (m -- ){
int a,b,c;
cin>>a>>b>>c;
g[a][b] = g[b][a] = min(g[a][b],c);
}
int res = prim();
if(res == INF) puts("impossible");
else cout<<res<<endl;

return 0;

}

(2) Kruskal

并查集 笔试不考

$O(mlogn)$

看边权,每次看最小边权的边,加后是否形成环,不形成环可加

2.最短路

image-20210805173335984

(1) 单源最短路 Dijkstra

AcWing 849. Dijkstra求最短路 I

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
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 505,INF = 0x3f3f3f3f;
int n,m;
int g[N][N],dist[N];
bool st[N];

int dij(){

memset(dist, INF, sizeof dist);
dist[1] = 0;
for (int i = 0; i < n; i ++ ){
// n个点
int t =-1 ;
for(int j = 1;j<=n;j++){
if( !st[j]&& (t==-1|| dist[t]>dist[j] ) )
t = j;
}

st[t] = true;

// 更新
for (int j = 1; j <= n; j ++ ){

dist[j] = min(dist[j],dist[t]+ g[t][j]);

}



}

return dist[n];
}

int main()
{
cin>>n>>m;
memset(g, INF, sizeof g);
while (m -- ){
int a,b,c;
cin>>a>>b>>c;
g[a][b] = min(g[a][b],c);

}

int res = dij();
if(res == INF) puts("-1");
else cout<<res<<endl;


return 0;
}

(2) 多源汇最短路 Floyd

AcWing 854. Floyd求最短路

$O(n^3)$

实际上是dp的思想,笔试不考dp,了解算法即可

$d[i][j] = min(d[i][j], d[i][k] + d[k][j])$

1->2-> 3 与 1->3 比较 ,更新

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
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 205,INF = 0x3f3f3f3f;
int n,m,Q;
int d[N][N];
int main()
{


cin>>n>>m>>Q;

memset(d, 0x3f, sizeof d);
for(int i = 1;i<=n; i++ ) d[i][i] = 0;

while (m -- ){


int a,b,c;

cin>>a>>b>>c;

d[a][b] = min(d[a][b],c);


}

for(int k= 1;k<=n;k++)
for(int i = 1;i<=n;i++)
for(int j = 1;j<=n;j++)
d[i][j] = min( d[i][j], d[i][k] + d[k][j] );



while(Q--){
int x,y;
cin>>x>>y;
if(d[x][y]>INF/2) puts("impossible");
else cout<<d[x][y]<<endl;
}



return 0;
}

3.关键路径

拓扑排序的 运用

最长路 递推

点:事件、边:活动

事件最早开始时间

事件最晚开始时间

活动最早开始时间

活动最晚开始时间

image-20210805181407071

image-20210806160659990

4.考题:2011-41、2012-7、2012-8、2013-9、2015-6、2015-42、2016-8、2017-42、2018-42、2019-5、2020-7、2020-8

2011-41

image-20210806151105388

image-20210806151217433

2012-7

image-20210806151359247

路径从小到大,

b:2,c:3,d:5,e:6,f:4

bcfde

选C

2012-8

image-20210806151438416

image-20210806151425436

A

2013-9

image-20210806151510412

求关键路径,最长路径

bdcg

bdeh

bfh

选C

2015-6

image-20210806151527963

image-20210806151537094

Kruskal : 每次选最小边,加入看是否成环

Prime:选相邻最小边

Kruskal:第一次选5,第二次选8

image-20210807093135980

Prime:v4开始

image-20210807093237097

(v2,v3)

选C

2015-42

image-20210806151558118

image-20210807093942975

image-20210807100345267

2016-8

image-20210806151619915

2:5 , 3: 7 , 4: 9, 5: 4 ,6:9

5、2、3、6、4

B

2017-42

image-20210806151656567

image-20210806151714194

image-20210807094035578

2.唯一

3.唯一条件: 任意环中边权都不同

2018-42

image-20210806161759548

image-20210807094626826

2种情况 2 + 2 + 3+ 2+ 2+3+2 = 16

TTL 时间,就是问TL -> BJ 距离长度

方案一能到,方案二不能到。

2019-5

image-20210806161819799

image-20210806161830371

d 最早开始时间: 起点到d的最长路 8+ 4 = 12

最晚开始时间: 求最长路 (27) - 端点到终点最长路(6)- 路径(7) = 14

image-20210807095153193

2020-7

image-20210806161855267

Kruskal : 每次选最小边,加入看是否成环,不成环就能加。

2020-8

image-20210806161911055

边权和最大

C:如果只有一条关键路径

D: 有多条关键路径