贪心算法: 合并果子(huffman tree)
c++
AcWing 148. 合并果子
/* Acwing 148. 合并果子 问题描述: 在一个果园里,达达已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。 达达决定把所有的果子合成一堆。 每一次合并,达达可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。 可以看出,所有的果子经过 n−1 次合并之后,就只剩下一堆了。 达达在合并果子时总共消耗的体力等于每次合并所耗体力之和。 因为还要花大力气把这些果子搬回家,所以达达在合并果子时要尽可能地节省体力。 假定每个果子重量都为 1,并且已知果子的种类数和每种果子的数目,你的任务是设计出合并的次序方案,使达达耗费的体力最少,并输出这个最小的体力耗费值。 例如有 3 种果子,数目依次为 1,2,9。 可以先将 1、2 堆合并,新堆数目为 3,耗费体力为 3。 接着,将新堆与原先的第三堆合并,又得到新的堆,数目为 12,耗费体力为 12。 所以达达总共耗费体力=3+12=15。 可以证明 15 为最小的体力耗费值。 输入格式: 输入包括两行,第一行是一个整数 n,表示果子的种类数。 第二行包含 n 个整数,用空格分隔,第 i 个整数 ai 是第 i 种果子的数目。 输出格式: 输出包括一行,这一行只包含一个整数,也就是最小的体力耗费值。 输入数据保证这个值小于 231。 数据范围: 1 ≤ n ≤ 10000, 1 ≤ ai ≤ 20000 解题思路: 首先,因为合并果子题目,合并时,并不是要求相邻合并,因此不是区间 DP(之前区间 DP介绍国 合并石子) 之前看过 huffman 树的同学应该知道,哈夫曼树,又称最优二叉树,是一棵带权值路径长度 (WPL,Weighted Path Length of Tree)最短的树,权值较大的节点离根更近。 本题的代价即为带权路径长度,使用 有限队列维护即可。 O(nlogn) */ #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <vector> using namespace std; const int N = 20010; int a[N], n; int solution_one() { int res = 0; priority_queue<int, vector<int>, greater<int> > pque; for (int i = 1; i <= n; i ++ ) { pque.push(a[i]); } for (int i = 1, x, y; i < n; i ++ ) { x = pque.top(); pque.pop(); y = pque.top(); pque.pop(); res += (x + y); pque.push(x + y); } return res; } int main() { scanf("%d", &n); for (int i = 1; i <= n; i ++ ) { scanf("%d", &a[i]); } int res = solution_one(); printf("%d\n", res); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效