【Acwing算法基础课】第六章贪心-Huffman树

148. 合并果子

题目: 148. 合并果子 - AcWing题库icon-default.png?t=M85Bhttps://www.acwing.com/problem/content/150/

 所有果子按照种类分成不同的堆, 比如三种果子分别是 1 2 9 个, 求合并的最小体力值

思路: 

解题方法来自acwing: AcWing 148. 合并果子 - AcWingicon-default.png?t=M85Bhttps://www.acwing.com/solution/content/3258/合并最小体力: 1 + 2 = 3; 3 + 9 = 12; 3 + 12 = 15

可以看成是一棵树, 一颗完全二叉树, 每个根节点都有左右两个儿子, 最终结果就是所有子节点相加, 拆分开看, 就是最底层节点的值*到根节点的路径长度, 所以值小的要放在深度深的位置

  1. 在所有点中, 最小的两个点一定深度最深, 且可以互为兄弟.

  2. 每次合并重量最小的两堆果子即可

时间复杂度

使用小根堆维护所有果子,每次弹出堆顶的两堆果子,并将其合并,合并之后将两堆重量之和再次插入小根堆中。

每次操作会将果子的堆数减一,一共操作 n−1次即可将所有果子合并成1堆。每次操作涉及到2次堆的删除操作和1次堆的插入操作,计算量是 O(logn)。因此总时间复杂度是 O(nlogn)。

代码

#include <iostream>
#include <algorithm>
#include <queue>
//贪心问题-huffman树 148.合并果子
using namespace std;

int main()
{
    int n;//果子的种类数
    scanf("%d", &n);//读取n
    //用小跟堆维护所有果子,每次弹出堆顶的两堆果子,并将其合并,合并之后将两堆重量之和再次插入小根堆中。
    priority_queue<int, vector<int>, greater<int>> heap;
    while (n -- )//枚举果子种类 读取每种果子个数
    {
        int x;//每种果子个数
        scanf("%d", &x);//读取个数
        heap.push(x);//放入堆中
    }

    int res = 0;//耗费的最小体力, 结果
    while (heap.size() > 1)//只要最后堆中是 > 1就继续合并
    {
        int a = heap.top(); heap.pop();//先取得第一个堆顶 a, 再把堆顶弹出
        int b = heap.top(); heap.pop();//在取得新的堆顶 b, 再把堆顶弹出
        res += a + b; //耗费的体力是a + b
        heap.push(a + b); //再把新的果子数加起来 放回堆中
    }

    printf("%d\n", res);//输出结果
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_65293439/article/details/128444770