小根堆/排序贪心

P1090 合并果子 题解复盘

模块:贪心算法

目标:每次合并当前最小的两堆果子,使总代价最小

基本信息

项目 内容
题目编号、来源 P1090 洛谷 / 合并果子
训练层级 A 模板题
知识版块 贪心、优先队列、小根堆

解题前 · 关键信号识别

维度 分析
目标、约束、底层结构 目标 :将 n 堆果子合并成一堆,使所有合并代价之和最小。 约束 :每次只能合并两堆果子,合并代价为两堆果子的重量之和。 底层结构:每次选择当前最优选择,属于优先队列贪心问题。
数据规模 n≤10000,如果每次排序寻找最小两个会增加复杂度,使用小根堆可以优化。
候选算法和依据 算法:贪心 + 小根堆。 依据:每次选择当前最小的两堆果子进行合并,可以使较小的代价尽量少参与后续合并,从而降低总代价。
复杂度预判 建堆 O(n),每次取出和加入操作 O(logn),共 n-1 次。 总时间复杂度 O(nlogn),空间复杂度 O(n)。

解题后 · 外化复盘

维度 内容
实现结构 / 核心思路 使用小根堆 priority_queue<int,vector<int>,greater<int>> 保存所有果子重量。每次取出堆顶的两个最小值 ab,合并代价加入答案 ans+=a+b,然后将新的果子重量 a+b 放回堆中。直到堆中只剩一堆果子。
错因回溯 1. 容易想到排序后取两个最小值,但是每次合并后还需要重新寻找最小值,效率较低。2. 合并代价可能较大,需要使用 long long 保存答案。❤️. 容易忘记将合并后的新果子重新加入堆中。
边界和易错点 1. 循环条件为 q.size()>1,只剩一堆时结束。2. 使用小根堆,不是默认大根堆。3. 每次合并后的新重量必须重新 push。4. 答案使用 long long
下次看到什么信号,我应该想到这个方法 看到:① 合并多个元素② 每次合并产生代价③ 要求总代价最小想到:优先队列贪心,每次取最小的两个。

AC 完整代码

cpp 复制代码
#include <iostream>
#include <queue>
using namespace std;

int main()
{
    int n;
    cin>>n;

    priority_queue<int,vector<int>,greater<int>> q;

    for(int i=0;i<n;i++)
    {
        int x;
        cin>>x;
        q.push(x);
    }

    long long ans=0;

    while(q.size()>1)
    {
        int a=q.top();
        q.pop();

        int b=q.top();
        q.pop();

        ans+=a+b;

        q.push(a+b);
    }

    cout<<ans;

    return 0;
}

P2676 USACO07DEC Bookshelf B 题解复盘

模块:贪心算法

目标:在奶牛总高度达到书架高度的前提下,选择最少数量的奶牛

基本信息

项目 内容
题目编号、来源 P2676 洛谷 / USACO07DEC Bookshelf B
训练层级 A 模板题
知识版块 贪心、排序、选择问题

解题前 · 关键信号识别

维度 分析
目标、约束、底层结构 目标 :选择尽可能少的奶牛,使它们的身高总和 ≥ 书架高度 B。 约束 :每头奶牛只能选择一次,选择数量越少越稳定。 底层结构:在满足总高度要求的情况下,让贡献大的元素优先加入,可以更快达到目标。
数据规模 N≤20000,奶牛数量较多,需要 O(nlogn) 或 O(n) 级别算法。
候选算法和依据 算法:贪心 + 排序。 依据:为了使用最少数量的奶牛,应该优先选择身高最高的奶牛,这样可以用更少的数量达到目标高度。
复杂度预判 排序 O(nlogn),遍历 O(n)。 总时间复杂度 O(nlogn),空间复杂度 O(n)。

解题后 · 外化复盘

维度 内容
实现结构 / 核心思路 1. 使用数组保存所有奶牛身高。 2. 按身高从大到小排序。 3. 从最高的奶牛开始累加高度,每选择一头奶牛,答案加一。 4. 当累计高度 sum>=B 时停止,此时选择的奶牛数量就是最少数量。
错因回溯 1. 容易想到从小到大选择,但这样会需要更多奶牛。 2. 高度总和可能超过 int 范围,因此累计高度使用 long long。 3. 排序方向错误会导致无法保证数量最少,需要降序排序。
边界和易错点 1. 一头奶牛高度可能已经达到 B,答案为 1。 2. 累加高度使用 long long。 3. 排序使用降序:greater<int>()。 4. 达到目标后及时退出循环。
下次看到什么信号,我应该想到这个方法 看到:① 最少选择多少个元素② 每个元素贡献不同③ 达到某个目标值想到:排序贪心,优先选择贡献最大的元素。

AC 完整代码

cpp 复制代码
#include <iostream>
#include <vector>
#include <queue>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <iomanip>
using namespace std;
int main(){
	int n,b;
	cin>>n>>b;
	vector<int> v;
	for(int i=0;i<n;i++){
		int a;
		cin>>a;
		v.push_back(a);
	}
	sort(v.begin(),v.end(),greater<int>());
	int ans=0;
	long long s=0;
	for(int i=0;i<n;i++){
		s+=v[i];
		ans++;
		if(s>=b) break;
	}
	cout<<ans;
	return 0;
}
相关推荐
程序员的园3 小时前
赋值运算符为什么要避免自赋值?
c++
Escalating_xu3 小时前
【C++ vector 深度解析】从常用接口、扩容机制与迭代器失效到核心模拟实现
java·c++·面试
牛艺翔3 小时前
C++ 基础知识
开发语言·c++
兔兔兔兔14 小时前
记录C++ 11
开发语言·c++
码匠许师傅4 小时前
【C++ 面试真题】32. 聊聊 C++ 的原子变量与无锁编程
java·c++·面试
wabs6664 小时前
关于栈【力扣150.逆波兰表达式求值的思考】
数据结构·c++·算法·leetcode··代码随想录
欧特克_Glodon4 小时前
OpenCV计算机视觉开发入门与实践<十七>:点运算与灰度变换概述
c++·人工智能·opencv·计算机视觉
牛油果子哥q4 小时前
C++序列式容器深度精讲:vector/list/deque底层实现、扩容原理、迭代器失效、性能对比、工程选型避坑
开发语言·c++·list
啦啦啦啦啦zzzz4 小时前
升序链表的定时器
linux·服务器·网络·数据结构·c++·链表
WBluuue4 小时前
数据结构与算法:带权并查集
数据结构·c++·算法