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

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

3周前 (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)的合并问题高效解决。关键在于“局部最优(每次最小合并)导致全局最优”的证明,体现了贪心算法的核心思想。实际应用中,该思路可扩展至类似资源合并优化场景,如哈夫曼编码树的构建。代码简洁且符合竞赛要求,是学习优先队列与贪心算法的经典案例。



原创内容 转载请注明出处

分享给朋友:

相关文章

力扣1137题:动态规划解泰波那契数 高效求解第N项的秘密

力扣1137题:动态规划解泰波那契数 高效求解第N项的秘密

一:重新解读题目泰波那契数列是一个充满数学趣味的递推序列:从第3项开始,每个数均为前三个数的和(即Tₙ₊₃ = Tₙ + Tₙ₊₁ + Tₙ₊₂)。当给定整数n时,需要高效计算出第n项的值。面对此类递...

牛客DP41精讲:当背包必须装满时,你的状态转移方程该如何调整?

牛客DP41精讲:当背包必须装满时,你的状态转移方程该如何调整?

题目重解我们面对一个经典背包问题的变体:给定n个物品,每个物品有重量w和价值v,背包容量为V。需要回答两个问题:1) 普通情况下能获得的最大价值;2) 必须恰好装满背包时的最大价值(若无法装满则输出0...

标题:洛谷B3617题解析:八进制转十六进制算法实现与优化(附AC100代码)

标题:洛谷B3617题解析:八进制转十六进制算法实现与优化(附AC100代码)

一、题目解读洛谷B3617题要求将输入的八进制字符串转换为十六进制表示。题目需处理大数场景,且对输入合法性有明确限制(长度不超过1000,仅包含0-7字符)。由于八进制与十六进制无法直接转换,需借助十...

牛客14496题解:括号最大深度问题(栈思想与代码优化)

牛客14496题解:括号最大深度问题(栈思想与代码优化)

一、题目解读牛客14496题要求计算给定括号字符串中的最大深度。例如,对于字符串 "(()())",最大深度为2。题目考察对括号嵌套结构的理解,以及如何通过编程找到最深嵌套层次。二...

力扣3112题解法:带时间限制的最短路径问题解析(C++代码)

力扣3112题解法:带时间限制的最短路径问题解析(C++代码)

一、题目解读力扣3112题要求解决带时间限制的最短路径问题:给定一个有向图,节点具有消失时间,需计算从起点到各节点的最短路径,且路径总时间不能超过节点的消失时间。题目难点在于需在传统最短路径算法(如D...

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

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

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

发表评论

访客

看不清,换一张

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