合并果子(贪心)
题目:合并果子(贪心)
题意:
有n堆果子,每次合并可以选择任意两堆合并,每次合并的消耗的体力是这两堆果子的重量和,求把n堆果子合并成1堆所需消耗体力的最小值。
输入格式
输入包括两行,第一行是一个整数 n,表示果子的种类数。
第二行包含 n 个整数,用空格分隔,第 i 个整数 ai 是第 i 种果子的数目。
输出格式
输出包括一行,这一行只包含一个整数,也就是最小的体力耗费值。
输入数据保证这个值小于 2^31。
数据范围
1≤n≤10000,
1≤ai≤20000
输入样例:
3
1 2 9
输出样例:
15
样例解释:
第一次合并选择1和2,消耗体力3,第二次合并选择3和9,消耗体力12。总共消耗的体力为3 + 12 = 15。
题目分析:贪心。
解题步骤:
- 每次选择序列中最小的两个元素进行合并,序列中添加一个新的元素,即这两个元素的和。
- 重复步骤1,直到序列中的元素为1个。
贪心策略证明:
如下图,如果把合并的过程看成一棵树,叶子节点为要合并的果子的数量。可以知道,越先合并的果子的深度越大,权重也会越大。例如下图中,a和b在合并的时候会被加1次,(a + b)和c在合并的时候会被加1次,所以a加了两次,b加了两次,c加了一次。
- 设贪心得出的答案是cnt,本题的正确答案是ans。
- 由于本题的答案ans是所有合并方案的最小值,所以必有ans <= cnt。
- 设h(x)为x在树中的深度,设在正确答案中有c < a且h(c) < h(a),则我们可以交换a和c的合并顺序,交换不影响其他点的权重。交换后,数值小的点权重变大,数值大的点权重变小,且a和c的权重改变量是相等的,所以交换后能够得到更小的答案。故有cnt <= ans。
- 由于ans <= cnt且cnt <= ans,得cnt = ans。
AC代码:
#include<iostream>
#include<queue>
using namespace std;
void solve(){
int n;
scanf("%d", &n);
priority_queue<int, vector<int>, greater<int> > pq;
while(n--){
int x;
scanf("%d", &x);
pq.push(x);
}
int res = 0;
while(pq.size() > 1){
int x = pq.top(); pq.pop();
int y = pq.top(); pq.pop();
res += x + y;
pq.push(x + y);
}
printf("%d\n", res);
}
int main(){
solve();
return 0;
}
时间复杂度:O(NlogN)。
空间复杂度:O(N)。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具