当前位置:首页 > 提高组 > 2004年NOIP提高组合并果子(洛谷P1090)题解:优先队列与贪心算法的完美应用

2004年NOIP提高组合并果子(洛谷P1090)题解:优先队列与贪心算法的完美应用

4个月前 (08-24)

2004年NOIP提高组合并果子(洛谷P1090)题解:优先队列与贪心算法的完美应用 贪心策略 优先队列 NOIP提高组 NOIP题解 洛谷题解 C++ 第1张

一、题目解读

合并果子(洛谷P1090)是2004年NOIP提高组的一道经典题目,原题链接:https://www.luogu.com.cn/problem/P1090。题目描述了一个果园场景:需要将N堆果子合并成一堆,每次合并消耗体力为两堆果子的重量之和,目标是通过设计合并顺序,使总消耗体力最小。数据范围要求1≤N≤10000,每堆果子重量1≤ai≤20000,需输出最小体力值。

二、解题思路

核心思路为贪心算法:每次优先合并当前最小的两堆果子,以降低后续合并的消耗。实现关键在于利用**优先队列最小堆)**自动维护果子堆的重量排序,确保每次取出的两堆果子重量最小,从而保证整体消耗最优。该策略符合哈夫曼(最优二叉树)的构建思想,即权值小的节点优先靠近叶节点,减少路径长度。

三、解题步骤

1. 输入处理:读取果子种类数N及每堆重量,存入优先队列q(小顶堆)。

2. 合并过程:

○ 循环直至队列仅剩一堆:

    弹出队首两堆果子a、b,计算合并消耗sum += a + b;

    将新堆a+b重新入队q,维持堆有序性。

3. 输出结果:最终sum即为最小体力消耗值。

四、代码与注释

#include <iostream>  
#include <queue>  
using namespace std;  

int main() {  
    int n, sum = 0;  
    cin >> n; // 输入果子种类数N  

    // 创建小顶堆优先队列,自动维护元素升序  
    priority_queue<int, vector<int>, greater<int>> q;  

    for(int i = 0; i < n; ++i) {  
        int weight;  
        cin >> weight; // 输入每堆果子重量  
        q.push(weight); // 初始化堆  
    }  

    while(q.size() > 1) { // 循环至仅剩一堆  
        int a = q.top(); q.pop(); // 取出最小两堆果子  
        int b = q.top(); q.pop();  
        sum += a + b; // 累加当前合并消耗  
        q.push(a + b); // 新堆入列  
    }  

    cout << sum << endl; // 输出最小体力值  
    return 0;  
}

注释解析:

● 优先队列q通过greater<int>参数指定为小顶堆,确保q.top()始终返回当前最小重量堆。

● 循环条件q.size() > 1保证合并次数为N-1,符合题目要求。

● sum变量累计每次合并的消耗,最终结果即为最优解。

五、总结

本解法通过贪心策略与优先队列的结合,将复杂度为O(NlogN)的合并问题高效解决。关键在于“局部最优(每次最小合并)导致全局最优”的证明,体现了贪心算法的核心思想。实际应用中,该思路可扩展至类似资源合并优化场景,如哈夫曼编码树的构建。代码简洁且符合竞赛要求,是学习优先队列与贪心算法的经典案例。



原创内容 转载请注明出处

分享给朋友:

相关文章

征服力扣704题:三步掌握经典二分查找算法

征服力扣704题:三步掌握经典二分查找算法

题目重解我们面对的是算法领域最经典的二分查找问题:在一个已排序的整数数组中,快速定位目标值的位置。就像在一本按字母顺序排列的字典中查找单词,我们不需要逐页翻阅,而是通过不断折半的方式快速缩小搜索范围,...

IOI 1994 洛谷1216:如何用动态规划高效解决数字三角形问题?附完整代码解析

IOI 1994 洛谷1216:如何用动态规划高效解决数字三角形问题?附完整代码解析

题目重解给定一个由数字组成的三角形结构,从顶部出发,每次可以移动到下方相邻的数字,最终到达底部。我们的目标是找到一条路径,使得路径上经过的数字总和最大。这个问题在实际中有许多应用场景,如最优路径规划、...

力扣145:递归之美 轻松掌握二叉树后序遍历

力扣145:递归之美 轻松掌握二叉树后序遍历

题目解读二叉树的后序遍历是一种基础且重要的树遍历方式,其遍历顺序为:先递归地后序遍历左子树,然后递归地后序遍历右子树,最后访问根节点。这种遍历方式特别适合需要先处理子节点再处理父节点的场景,如内存释放...

力扣965题深度解析:单值二叉树的判断技巧

力扣965题深度解析:单值二叉树的判断技巧

重新解读题目 判断一棵二叉树是否为“单值二叉树”,即所有节点的值是否完全相同。题目看似简单,实则考验对树结构递归特性的理解。若一棵树的所有节点值相同,其必然满足:根节点与左右子树的值一致,且...

【洛谷1184题解析】用C++高效解决地点匹配问题(附代码与解题思路)

【洛谷1184题解析】用C++高效解决地点匹配问题(附代码与解题思路)

一、题目解读洛谷1184题要求处理一组地点列表与行程记录,统计其中匹配的天数。题目难点在于高效处理带有空格的字符串输入,以及快速判断每日行程是否在高手可去地点集合中。需要兼顾输入格式解析与算法效率。二...

洛谷1220题解:动态规划与区间DP优化解法(附代码注释)

洛谷1220题解:动态规划与区间DP优化解法(附代码注释)

一、题目解读洛谷1220题要求计算在n个位置放置灯的情况下,通过关闭连续区间灯并移动至区间端点,使得总耗电量最小。需考虑灯的功率与位置差异,设计高效的算法求解最优策略。二、解题思路1. 动态规划 +...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。