题目描述
在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。
每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过 n−1 次合并之后, 就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。
因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为 1 ,并且已知果子的种类 数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。
例如有 3 种果子,数目依次为 1 , 2 , 9 。可以先将 1 、 2 堆合并,新堆数目为 3 ,耗费体力为 3 。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为 12 ,耗费体力为 12 。所以多多总共耗费体力 3+12=15 。可以证明 15 为最小的体力耗费值。
输入格式
共两行。
第一行是一个整数 n(1≤n≤10000) ,表示果子的种类数。
第二行包含 n 个整数,用空格分隔,第 i 个整数 ai(1≤ai≤20000) 是第 i 种果子的数目。
输出格式
一个整数,也就是最小的体力耗费值。输入数据保证这个值小于 2^31 。
输入输出样例
输入 #1复制
3 1 2 9
输出 #1复制
15
说明/提示
对于 30% 的数据,保证有n≤1000:
对于 50% 的数据,保证有 n≤5000;
对于全部的数据,保证有 n≤10000。
#include <iostream>
#include <queue>
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 num;
cin >> num;
pq.push(num);
}
int totalCost = 0;
// 从最小堆中取出两个最小值进行合并,并将合并后的结果放回堆中,直到堆中只剩下一个元素为止
while (pq.size() > 1) {
int a = pq.top(); // 取出堆顶元素
pq.pop(); // 移除堆顶元素
int b = pq.top(); // 取出新的堆顶元素
pq.pop(); // 移除新的堆顶元素
int newPile = a + b; // 合并两堆果子
totalCost += newPile; // 更新总体力消耗
pq.push(newPile); // 将合并后的结果放回堆中
}
cout << totalCost; // 输出合并总体力消耗
return 0;
}
priority_queue
是C++ STL中的一个容器适配器,它提供了基于优先级的元素访问,通常用于实现优先队列。priority_queue
中的元素按照一定的顺序进行排列,并且在访问时具有反向顺序,即最重要的(最大或最小)元素总是位于队列的前面。
以下是priority_queue
的基本用法介绍:
- 包含头文件
#include <queue>
- 创建
priority_queue
priority_queue<int> pq; // 创建一个默认的最大堆
- 创建最小堆
priority_queue<int, vector<int>, greater<int>> minPq; // 创建一个最小堆
- 插入元素
pq.push(5); // 向最大堆中插入元素
minPq.push(3); // 向最小堆中插入元素
- 获取堆顶元素
int topElement = pq.top(); // 获取最大堆的堆顶元素
int minTopElement = minPq.top(); // 获取最小堆的堆顶元素
- 弹出堆顶元素
pq.pop(); // 弹出最大堆的堆顶元素
minPq.pop(); // 弹出最小堆的堆顶元素
- 获取堆的大小
int size = pq.size(); // 获取最大堆的大小
int minSize = minPq.size(); // 获取最小堆的大小
priority_queue
的底层实现通常使用堆(heap)数据结构,因此在插入、删除元素时具有较好的时间复杂度。同时,通过使用不同的比较函数可以实现最大堆和最小堆,从而满足不同的业务需求