csp信奥赛C++高频考点专项训练之贪心算法 --【哈夫曼贪心】:合并果子

csp信奥赛C++高频考点专项训练之贪心算法 --【哈夫曼贪心】:合并果子

题目描述

在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。

每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过 n − 1 n-1 n−1 次合并之后, 就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。

因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为 1 1 1,并且已知果子的种类数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。

例如有 3 3 3 种果子,数目依次为 1 1 1, 2 2 2, 9 9 9。可以先将 1 1 1、 2 2 2 堆合并,新堆数目为 3 3 3,耗费体力为 3 3 3 。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为 12 12 12,耗费体力为 12 12 12。所以多多总共耗费体力 = 3 + 12 = 15 =3+12=15 =3+12=15。可以证明 15 15 15 为最小的体力耗费值。

输入格式

共两行。

第一行是一个整数 n ( 1 ≤ n ≤ 10 4 ) n(1\leq n\leq 10^4) n(1≤n≤104),表示果子的种类数。

第二行包含 n n n 个整数,用空格分隔,第 i i i 个整数 a i ( 1 ≤ a i ≤ 2 × 10 4 ) a_i(1\leq a_i\leq 2\times 10^4) ai(1≤ai≤2×104) 是第 i i i 种果子的数目。

输出格式

一个整数,也就是最小的体力耗费值。输入数据保证这个值小于 2 31 2^{31} 231。

输入输出样例 #1
输入 #1
复制代码
3 
1 2 9 
输出 #1
复制代码
15
说明/提示

对于 30 % 30\% 30% 的数据,保证有 n ≤ 10 3 n \le 10^3 n≤103;

对于 50 % 50\% 50% 的数据,保证有 n ≤ 5 × 10 3 n \le 5\times10^3 n≤5×103;

对于全部的数据,保证有 n ≤ 10 4 n \le 10^4 n≤104。

思路分析

这道题要求将若干堆果子合并成一堆,每次合并两堆,消耗的体力等于两堆重量之和,目标是最小化总消耗。这是典型的哈夫曼树问题,最优策略是每次选择当前最小的两堆进行合并。使用小根堆(优先队列)可以高效实现:将所有果子数插入小根堆,循环取出最小的两个,合并后放回堆中,累加消耗,直到堆中只剩一堆。时间复杂度 O(n log n),空间复杂度 O(n)。

代码实现

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

int main() {
    int n; // 果子种类数
    cin >> n;
    priority_queue<int, vector<int>, greater<int>> pq; // 小根堆
    for (int i = 0; i < n; ++i) {
        int a; // 每种果子的数目
        cin >> a;
        pq.push(a);
    }
    long long ans = 0; // 最小体力耗费值
    while (pq.size() > 1) { // 直到只剩一堆
        int x = pq.top(); pq.pop(); // 取最小堆
        int y = pq.top(); pq.pop(); // 取次小堆
        int s = x + y; // 合并后的新堆大小
        ans += s; // 累加消耗
        pq.push(s); // 新堆入堆
    }
    cout << ans << endl;
    return 0;
}

功能分析

  1. 输入处理 :读取果子种类数 n 和每种的数目,依次插入小根堆。
  2. 合并过程:每次从堆顶取出最小的两堆(堆自动维护最小堆性质),合并后得到的新堆大小等于两者之和,累加到答案,并将新堆放回堆中。
  3. 循环终止:当堆中只剩一堆时结束,此时答案即为最小体力耗费值。
  4. 正确性:哈夫曼算法贪心性质保证每次合并最小的两堆能得到全局最优解,优先队列模拟了该过程。
  5. 边界情况 :若 n=1,不进入循环,直接输出 0(无需合并,体力消耗为0),符合题目要求。

各种学习资料,助力大家一站式学习和提升!!!

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main(){
	cout<<"##########  一站式掌握信奥赛知识!  ##########";
	cout<<"#############  冲刺信奥赛拿奖!  #############";
	cout<<"######  课程购买后永久学习,不受限制!   ######";
	return 0;
}

【秘籍汇总】(完整csp信奥赛C++学习资料):

1、csp/信奥赛C++,完整信奥赛系列课程(永久学习):

https://edu.csdn.net/lecturer/7901 点击跳转

2、CSP信奥赛C++竞赛拿奖视频课:

https://edu.csdn.net/course/detail/40437 点击跳转

https://edu.csdn.net/course/detail/41081 点击跳转

3、csp信奥赛高频考点知识详解及案例实践:

CSP信奥赛C++动态规划:
https://blog.csdn.net/weixin_66461496/category_13096895.html点击跳转

CSP信奥赛C++标准模板库STL:
https://blog.csdn.net/weixin_66461496/category_13108077.html 点击跳转

信奥赛C++提高组csp-s知识详解及案例实践:
https://blog.csdn.net/weixin_66461496/category_13113932.html 点击跳转

4、csp信奥赛冲刺一等奖有效刷题题解:

CSP信奥赛C++初赛及复赛高频考点真题解析(持续更新): https://blog.csdn.net/weixin_66461496/category_12808781.html 点击跳转

信奥赛C++提高组csp-s初赛&复赛真题题解(持续更新):
https://blog.csdn.net/weixin_66461496/category_13125089.html 点击跳转

5、GESP C++考级真题题解:

GESP(C++ 一级+二级+三级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12858102.html 点击跳转

GESP(C++ 四级+五级+六级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12869848.html 点击跳转

GESP(C++ 七级+八级)真题题解(持续更新):
https://blog.csdn.net/weixin_66461496/category_13117178.html 点击跳转

· 文末祝福 ·

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main(){
	cout<<"跟着王老师一起学习信奥赛C++";
	cout<<"    成就更好的自己!       ";
	cout<<"  csp信奥赛一等奖属于你!   ";
	return 0;
}
相关推荐
叼烟扛炮2 小时前
C++第二讲:类和对象(上)
数据结构·c++·算法·类和对象·struct·实例化
天疆说2 小时前
【哈密顿力学】深入解读航天器交会最优控制中的Hamilton函数
人工智能·算法·机器学习
wuweijianlove3 小时前
关于算法设计中的代价函数优化与约束求解的技术7
算法
leoufung3 小时前
LeetCode 149: Max Points on a Line - 解题思路详解
算法·leetcode·职场和发展
样例过了就是过了3 小时前
LeetCode热题100 最长公共子序列
c++·算法·leetcode·动态规划
HXDGCL3 小时前
矩形环形导轨:自动化循环线的核心运动单元解析
运维·算法·自动化
谭欣辰3 小时前
C++ 排列组合完整指南
开发语言·c++·算法
代码中介商4 小时前
银行管理系统的业务血肉 —— 流程、状态机、输入校验与持久化(下篇)
c语言·算法
橙子也要努力变强4 小时前
信号捕捉底层机制-机理篇2
linux·服务器·c++