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

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值