数据结构_第8讲 最小生成树、最短路、关键路径

本文深入探讨了图论中的重要算法,包括Prim和Kruskal两种最小生成树算法,单源最短路的Dijkstra算法以及多源汇最短路的Floyd算法,并结合实例解析了它们的应用。此外,还介绍了关键路径在最长路问题中的应用。这些算法在解决网络连接、路径优化等问题中具有广泛的实际价值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

1.最小生成树 MST

无向图

不一定唯一

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

(1) Prim

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

堆优化: O ( m l o g n ) O(mlogn) 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++:

#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 ( m l o g n ) O(mlogn) O(mlogn)

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

2.最短路

image-20210805173335984

(1) 单源最短路 Dijkstra

AcWing 849. Dijkstra求最短路 I

#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 ) O(n^3) O(n3)

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

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

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

#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: 有多条关键路径

对任意给定的图(顶点数不小于20,边数不少于30,图的类型可以是有向图、无向图、有向网、无向网),能够输入图的顶点和边(或弧)的信息,并存储到相应存储结构(邻接矩阵、邻接表、十字链表、邻接多重表,任选其中两种类型),对自己所创建的图完成以下操作: 1、 对无向图求每个顶点的度,或对有向图求每个顶点的入度和出度(5分) 2、 完成插入顶点和边(或弧)的功能(5分) 3、 完成删除顶点和边(或弧)的功能(5分) 4、 两种存储结构的转换(5分),如果其中一种存储结构为十字链表或邻接多重表则增加5分。 5、 输出图的深度优先遍历序列或广度优先遍历序列(5分) 6、 求图的深度优先或广度优先的生成树(或生成森林)(存储结构为孩子-兄弟链表),并对生成树进行遍历(15分) 7、 判断图的连通性,输出连通分量的个数(5分) 8、 判断图中是否存在环,无向图5分,有向图10分 9、 给出顶点u和v,判断u到v是否存在路径(5分) 10、求顶点u到v的一条简单路径(10分) 11、求顶点u到v的所有简单路径(15分) 12、求顶点u到v的最短路径(10分) 13、求顶点u到其余各顶点的最短路径(15分) 14、求任两个顶点之间的最短路径(15分) 15、求最小生成树(15分) 16、对于有一个源点和一个汇点的有向网,求关键路径(20分)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值