第3关:STL模板之queue实例三:合并果子


任务描述

本关任务:果园里有N堆不同重量的果子,现在需要将它们合成一堆,每次只能合并两堆果子,并且消耗两堆果子重量和的能量,请问如何将所有果子合成一堆消耗最少的能量。

相关知识

为了完成本关任务,你需要掌握:1.优先队列,2.求解思路。

优先队列

优先队列priority queue是一种特殊的队列结构。基础队列的特性是先进先出:在队尾添加新的元素,在队首访问和删除。而优先队列中的元素被赋予优先级的概念:当访问或删除元素时,具有最高优先级的元素最先被操作,也就是说优先队列具有最高级先出first in, largest out的特性,通常具体采用堆的数据结构来实现。堆是一种比较复杂的数据结构,本实例重点在学习STL模板中的优先队列,所以不过多介绍堆的具体实现。

优先队列priority_queue容器的C++标准头文件为queue,提供的基础操作及实例如下:

  • empty判断优先队列是否为空,若空则返回true,否则返回false
  •  size返回当前优先队列的大小,即优先队列里元素的个数;
  • top返回优先队列的最高优先级的元素;
  • push将元素添加到优先队列,STL中的优先队列会根据元素的优先级自动调整;
  • pop移除优先队列的队首元素。
 
  1. #include <iostream> // std::cout
  2. #include <queue> // std::priority_queue
  3. int main (){
  4. std::priority_queue<int> mypq; // 创建一个整型的优先队列,默认数值越大优先级越高
  5. mypq.push(30); // 加入元素
  6. mypq.push(100); // 加入元素
  7. mypq.push(25);
  8. mypq.push(40);
  9. std::cout << "Popping out elements...";
  10. while (!mypq.empty()){ // 判断优先队列是否为空
  11. std::cout << ' ' << mypq.top(); // 获取队首(最高优先级)元素
  12. mypq.pop(); // 移除队首元素
  13. }
  14. std::cout << '\n'; // 输出结果为100 40 30 25
  15. return 0;
  16. }

创建一个优先队列,需要制定数据类型的优先级比较方式,基础的数据类型会有默认的优先级比较方式,例如上面的整型数据默认的比较方式为数值越大优先级越高。

求解思路

显然本问题就是一个典型的优先队列的问题,每次选择重量最小的两堆果子合并,最终消耗的能量是最少的。因为重量大的果子重复搬运比重量小的果子重复搬运会增加额外的能量消耗。

通过创建一个整型的优先队列pque可以直接求解该问题,需要注意的是优先级为数值越大优先级越高,而本问题需要的是数值越小优先级越高,因此我们可以通过一个巧妙的方式来求解:将所有果子重量乘以-1转化为负值。具体步骤如下,定义一个整型变量ans存储能量消耗,初始为0

  • step1:将所有果子重量加入优先队列pque
  • step2:若队列非空,则获取队首元素存入整型变量q1并移除队首元素,否则算法结束;
  • step3:若队列非空,则获取队首元素存入整型变量q2并移除队首元素,否则算法结束;
  • step4:合并两堆果子q1q2,并将合并后的重量q1+q2添加到队列中,更新ansans=ans-q1-q2
  • step5:跳转到step2

另外,STL也提供了通过重载结构体的方式自定义优先级,如下:

 
  1. // 方式一
  2. priority_queue<int,vector<int>, greater<int> > que1; // x小的优先级高
  3. // 方式二
  4. struct comp{
  5. bool operator()(int x,int y){
  6. return x>y; //重载()的方式,x小的优先级高
  7. }
  8. };
  9. priority_queue<int, vector<int>, comp> que2; // 从小到大的优先队列
  10. // 方式三
  11. struct node {
  12.   int x, y;
  13.   friend bool operator < (node a, node b) {
  14.     return a.x > b.x; //结构体类型的方式,x小的优先级高
  15.   }
  16. };
  17. priority_queue<node> que3;
编程要求

本关的编程任务是补全右侧代码片段mainBeginEnd中间的代码,具体要求如下:

  • main中,读取数据,基于优先队列的数据结构求解N堆果子合并的问题,计算出最少能量,并输出结果。
测试说明

平台将自动编译补全后的代码,并生成若干组测试数据,接着根据程序的输出判断程序是否正确。

以下是平台的测试样例:

测试输入: 4 3 12 9 11 预期输出: 70 样例解释: 首先合并3 9两堆果子并形成重量为12的新堆果子,消耗能量12,当前还剩11 12 12三堆果子 接着合并11 12两堆果子并形成重量为23的新堆果子,消耗能量23,当前还剩12 23两堆果子 最后合并余下的两堆果子,消耗能量35 总共消耗能量为12+23+35=70

输入格式: 第一行:果子堆数N 第二行:N堆果子的重量 输出格式: 一行:消耗的最少能量

//
//  main.cpp
//  step3
//
//  Created by ljpc on 2018/9/13.
//  Copyright © 2018年 ljpc. All rights reserved.
//

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

int main(int argc, const char * argv[]) {
    
    // 请在这里补充代码,完成本关任务
    /********* Begin *********/
    
    int N;
    cin >> N;
    priority_queue<int, vector<int>, greater<int>> pq; // 创建最小堆

    for (int i = 0; i < N; ++i) {
        int weight;
        cin >> weight;
        pq.push(weight);
    }

    int total_energy = 0;

    while (pq.size() > 1) {
        int first = pq.top();
        pq.pop();
        int second = pq.top();
        pq.pop();
        int new_weight = first + second;
        total_energy += new_weight;
        pq.push(new_weight);
    }

    cout << total_energy << endl;

    /********* End *********/
    
    return 0;
}

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你好!对于你的问题,可以使用STL中的queue模板来解决。假设你有一个数组arr,你需要找到一个最少个数的子数组,使得子数组的和大于等于一个给定的值target。下面是一个使用queue模板实现的示例代码: ```cpp #include <iostream> #include <queue> using namespace std; int findMinSubArray(int arr[], int n, int target) { queue<int> q; int currentSum = 0; int minSize = INT_MAX; for (int i = 0; i < n; i++) { currentSum += arr[i]; q.push(arr[i]); while (currentSum >= target) { minSize = min(minSize, (int)q.size()); currentSum -= q.front(); q.pop(); } } return minSize == INT_MAX ? 0 : minSize; } int main() { int arr[] = {1, 4, 2, 3, 5}; int n = sizeof(arr) / sizeof(arr[0]); int target = 10; int minSize = findMinSubArray(arr, n, target); cout << "The minimum number of elements in a subarray with sum >= " << target << " is: " << minSize << endl; return 0; } ``` 在这个示例代码中,我们使用了一个队列q来存储当前子数组的元素。我们通过遍历数组arr,并将元素依次加入队列中,同时更新当前子数组的和currentSum。当currentSum大于等于目标值target时,我们开始从队列中移除元素,直到currentSum小于target。在这个过程中,我们记录队列的大小,也就是子数组的元素个数,并不断更新最小值minSize。最后,我们返回minSize作为结果,如果没有符合条件的子数组,则返回0。 在上面的示例代码中,给定的数组arr为{1, 4, 2, 3, 5},目标值target为10。运行结果显示最少元素个数为3,即子数组{4, 2, 3}的和大于等于10。 希望这个示例能帮到你!如果还有其他问题,请随时问我。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值