• 算法设计与分析复习--贪心(二)


    上一篇

    算法设计与分析复习–贪心(一)

    哈夫曼编码

    在这里插入图片描述
    在这里插入图片描述
    产生这种前缀码的方式称为哈夫曼树

    哈夫曼树相关习题AcWing 148. 合并果子

    #include 
    #include 
    #include 
    #include 
    
    using namespace std;
    
    const int N = 10010;
    
    int n;
    priority_queue, greater > heap;
    
    int main()
    {
        scanf("%d", &n);
        
        for (int i = 0; i < n; i ++)
        {
            int x;
            scanf("%d", &x);
            heap.push(x);
        }
        
        int res = 0;
        while (heap.size() > 1)
        {
            int x = 0;
            x += heap.top(); heap.pop();
            x += heap.top(); heap.pop();
            heap.push(x);
            res += x;
        }
        printf("%d", res);
        return 0;
    }
    
    • 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

    在这里插入图片描述

    单源最短路

    最短路问题

    Dijkstra方法
    在这里插入图片描述
    在这里插入图片描述

    稠密图下

    AcWing 849. Dijkstra求最短路 I

    使用邻接矩阵来存

    #include 
    #include 
    #include 
    
    using namespace std;
    
    const int N = 510;
    
    int g[N][N], n, m;
    int dist[N];
    bool st[N];
    
    int dijkstra()
    {
        memset(dist, 0x3f, sizeof dist);
        dist[1] = 0;//这里不能初始化st[1]因为此时还没拓展边
        
        for (int i = 1; i < n; i ++)
        {
            int t = -1;
            for (int j = 1; j <= n; j ++)
                if (!st[j] && (t == -1 || dist[j] < dist[t]))
                    t = j;
            
            st[t] = true;//找到连接当前结点的最短的一条边了
            
            for (int j = 1; j <= n; j ++)
                dist[j] = min(dist[j], dist[t] + g[t][j]);//松弛操作
        }
        
        if (dist[n] > 0x3f3f3f3f >> 1) return -1;
        else return dist[n];
    }
    
    int main()
    {
        memset(g, 0x3f, sizeof g);
        scanf("%d%d", &n, &m);
        
        for (int i = 0; i < m; i ++)
        {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            g[a][b] = min(g[a][b], c);
        }
        
        printf("%d", dijkstra());
        return 0;
    }
    
    • 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

    在这里插入图片描述

    最小生成树

    问题描述:设G = (V, E)是无向连通带权图。E中每条边(v, w)的权为c[v][w]。最小生成树问题就是要在G的所有生成树中,找到权值最小的那颗生成树。

    最小生成树与二分图

    up讲解

    Kruskal算法

    AcWing 859. Kruskal算法求最小生成树

    在这里插入图片描述

    从边的角度生成最小生成树,将边按照从小到大排序,并一次回放到结点集中,在进行判断是否有产生环,如果没有产生环就说明这个边的添加是可行的,直至添加n - 1个边,否则不能生成
    判断是否有环产生使用并查集

    适用于稀疏图,由于处理的是边的信息所以定义这个结构体

    #include 
    #include 
    #include 
    
    using namespace std;
    
    const int N = 100010, M = 200010;// 边较少是稀疏图
    
    struct edge
    {
        int a, b, c;
    }e[M];
    
    int n, m, f[N];
    
    bool cmp(edge x, edge y)
    {
        return x.c < y.c;
    }
    
    int find(int x)
    {
        if (x != f[x]) f[x] = find(f[x]);
        return f[x];
    }
    
    void kruskal()
    {
        sort(e, e + m, cmp);
        
        int res = 0, cnt = 0;
        
        for (int i = 0; i < m; i ++)
        {
            int a = e[i].a, b = e[i].b, c = e[i].c;
            a = find(a), b = find(b);//并查集至少需要将两个点find一次,不如直接记下来
            if (a != b)
            {
                f[a] = b;
                res += c;
                cnt ++;
            }
        }
        
        if (cnt < n - 1) puts("impossible");
        else printf("%d", res);
    }
    
    int main()
    {
        scanf("%d%d", &n, &m);
        
        for (int i = 1; i <= n; i ++) f[i] = i; 
            
        for (int i = 0; i < m; i ++) 
        {
            scanf("%d%d%d", &e[i].a, &e[i].b, &e[i].c);
        }
        kruskal();
        return 0;
    }
    
    • 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

    在这里插入图片描述

    Prim算法

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

    在这里插入图片描述
    将顶点集分为已选顶点集合和未选顶点集合,然后优先选择连接两个集合的权值最小的边

    适用于稠密图,用邻接矩阵存的

    #include 
    #include 
    #include 
    
    using namespace std;
    
    const int N = 510;
    
    int g[N][N], n, m;
    int dist[N];
    bool st[N];
    
    void prim()
    {
        memset(dist, 0x3f, sizeof dist);
        
        int res = 0;
        for (int i = 0; i < n; i ++)
        {
            int t = -1;
            for (int j = 1; j <= n; j ++)
                if (!st[j] && (t == -1 || dist[j] < dist[t]))
                    t = j;
            
            st[t] = true;
            
            //第一个结点不做处理
            if (i && dist[t] == 0x3f3f3f3f){// 不连通
                puts("impossible");
                return;
            }
            if (i) res += dist[t];//加权重
            
            for (int j = 1; j <= n; j ++)
                dist[j] = min(dist[j], g[t][j]);//和dijkstra的区别,算的不是从起点到的距离而是两个点的距离,所以不加
        }
        printf("%d", res);
        
    }
    
    int main()
    {
        memset(g, 0x3f, sizeof g);
        scanf("%d%d", &n, &m);
        
        for (int i = 0; i < m; i ++)
        {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            g[a][b] = g[b][a] = min(g[a][b], c);//无权图两边都要
        }
        
        prim();
        return 0;
    }
    
    • 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

    在这里插入图片描述

    多机调度问题

    设有n个独立的作业{1, 2, …,n}, 由m台相同的机器{ M 1 , M 2 , . . . , M m M_1, M_2, ..., M_m M1,M2,...,Mm}进行加工处理,作业 i i i 所需的处理时间为 t i t_i ti(1 <= i <= n),每个作业均可在任何一台机器上加工处理, 但不可间断、拆分。要求给出一种作业调度方案 ,使得n个作业在尽可能短的时间内被m个机器加工完成。

    贪心策略:采取最长处理时间作业优先

    #include 
    #include 
    #include 
    #include 
    
    using namespace std;
    typedef pair PII;
    
    const int N = 100010;
    
    int a[N], n, m;
    priority_queue, greater > heap;
    
    bool cmp(int x, int y)
    {
        return x > y;
    }
    
    int main()
    {
        scanf("%d%d", &n, &m);
        
        for (int i = 0; i < n; i ++) scanf("%d", &a[i]);
        for (int i = 1; i <= m; i ++) heap.push({0, i});
        
        sort(a, a + n, cmp);
        
        int res = 0;
        for (int i = 0; i < n; i ++)
        {
            auto t = heap.top();
            heap.pop();
            t.first += a[i];
            
            res = max(res, t.first);
            heap.push(t);
        }
        
        printf("%d", res);
        return 0;
    }
    
    • 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

    在这里插入图片描述
    在这里插入图片描述

    下一篇

    未完待续

  • 相关阅读:
    Mysql索引、事务、存储引擎
    Bootstrap的导航菜单组件相关知识
    高薪程序员&面试题精讲系列147之你熟悉哪些加密算法(上篇)?如何保证项目的安全性?
    x86-Hardware-Compatibility-Assessment-and-Porting-Guide
    Android SIP软电话,通话录音,VoIP电话,linphone电话
    std::bind 源码分析
    map和set详解
    我的NVIDIA开发者之旅——为 NVIDIA Jetson Nano 运行 Docker 容器(学习笔记)
    Java版直播商城免 费 搭 建:电商、小程序、三级分销及免 费 搭 建,平台规划与营销策略全掌握
    数据结构与算法:栈(java)
  • 原文地址:https://blog.csdn.net/m0_64372178/article/details/134492422