原题链接:
题目概述
这道题目描述了一个果园合并果子的问题,要求我们找到合并所有果堆的最小体力消耗方案。这是一个典型的贪心算法问题,也是优先队列(堆)数据结构的经典应用。
解题思路
要最小化合并果子的体力消耗,我们应该每次都合并当前最小的两堆果子。这种策略可以确保较大的果堆尽可能少地被重复合并。具体步骤如下:
将所有果堆的重量放入最小堆(优先队列)中
每次取出两个最小的果堆进行合并
将合并后的新果堆重量重新放入堆中
累加每次合并的体力消耗
重复上述过程直到只剩一堆果子
参考程序
#include<bits/stdc++.h>
#define i64 long long // 定义长整型别名,防止大数溢出
#define endl "\n"
using namespace std;
// 定义最小优先队列,存储果子堆的重量
priority_queue<int, vector<int>, greater<int>> pq;
int n, x; // n-果子种类数,x-临时变量
int main() {
cin >> n; // 输入果子种类数
// 读取每种果子的数量并存入优先队列
for(int i = 1; i <= n; i++) {
cin >> x;
pq.push(x); // 将果子数量加入最小堆
}
i64 sum = 0; // 总体力消耗,使用长整型防止溢出
// 当堆中还有多于一堆果子时继续合并
while(pq.size() > 1) {
// 取出当前最小的两堆果子
int a = pq.top(); pq.pop();
int b = pq.top(); pq.pop();
// 累加本次合并的体力消耗
sum += (a + b);
// 将合并后的新堆重新放入优先队列
pq.push(a + b);
}
// 输出最小体力消耗值
cout << sum;
return 0;
}
代码解析
数据结构选择:使用
priority_queue
实现最小堆,确保每次都能快速获取最小的两个元素。输入处理:首先读取果子种类数n,然后读取n个果堆的重量并存入优先队列。
合并过程:
使用while循环,直到堆中只剩一堆果子
每次取出两个最小的果堆a和b
将a+b累加到总消耗sum中
将合并后的新堆(a+b)重新放入堆中
输出结果:最终输出累计的体力消耗值sum。
复杂度分析
时间复杂度:O(n log n),每个元素插入和删除堆的操作都是O(log n),共进行O(n)次操作
空间复杂度:O(n),需要存储所有果堆的重量
示例验证
以题目中的样例为例:
输入:3种果子,重量分别为1、2、9
初始堆:[1, 2, 9]
第一次合并:1+2=3,消耗3 → 堆:[3, 9],sum=3
第二次合并:3+9=12,消耗12 → 堆:[12],sum=15
输出结果:15