P1090 [NOIP 2004 提高组] 合并果子
题目概述
这道题目描述了一个果园合并果子的问题,要求我们找到合并所有果堆的最小体力消耗方案。这是一个典型的贪心算法问题,也是优先队列(堆)数据结构的经典应用。
解题思路
要最小化合并果子的体力消耗,我们应该每次都合并当前最小的两堆果子。这种策略可以确保较大的果堆尽可能少地被重复合并。具体步骤如下:
- 
将所有果堆的重量放入最小堆(优先队列)中 
- 
每次取出两个最小的果堆进行合并 
- 
将合并后的新果堆重量重新放入堆中 
- 
累加每次合并的体力消耗 
- 
重复上述过程直到只剩一堆果子 
参考程序
#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 
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号