c++优先队列简介及例题:5.4.1 围栏修复

优先队列,其实就是个队列,只不过里面的元素会被自动按一定的顺序来排列。

可以是递增顺序,也可以是递减顺序。

写法如下:

头文件:

#include<queue>

定义一个优先队列:
 

priority_queue<int,vector<int>,greater<int>> myqueue
//第一个参数是你队列的数据类型,可以是int,string,double等等
//第二个参数是容器类型,好像用vector就够了
//第三个是排序方式,升序用greater<int>,降序用less<int>

对优先队列的操作:

 //弹出队列头元素,注意不是front!!!
myqueue.pop()
//其它的和普通的队列没区别。。。

例子:

#include<bits/stdc++.h>
#include<queue>
using namespace std;
int main()
{
     priority_queue<int,vector<int>,greater<int>>myqueue;
     myqueue.push(3);
     myqueue.push(1);
     myqueue.push(2);
     myqueue.push(5);
     myqueue.push(4);
    while(myqueue.size()!=0)
    {
    	cout<<myqueue.top()<<" ";
    	myqueue.pop();
    }
}

//输出的是1 2 3 4 5,可以看出,这个优先队列是自动升序排列的

例题:
题目描述
农民 John 希望修复围绕农场的一小段围栏。他测量了一下,发现需要N (1 <= N <= 20,000) 根木头,每根都有某一个整数长度 Li (1 <= Li <= 50,000) 单位长度。他买了一根很长的很长的木头,正好能够锯出他所需要的N根木头。(即它的长度正好等于Li的总和) FJ 忽略锯口,锯掉的木屑产生的长度损失忽略不计,你也可以忽略它。
FJ 遗憾的发现他自己没有用于切木头的锯子,所以他就带着那根很长的木头来到了农民 Don的农场,想问他借一个锯子。
农民 Don是一个保守的资本家,他不愿意借锯子给 FJ ,但愿意自己来切这N-1刀,每一次都向FJ收取费用。每次的收费正好等于你要锯的那根木头的总长度。例如,你要锯一根长度为21的木头,就花费21分钱。
农民 Don 然后让农民 John 自己决定每次锯木头的顺序和位置。帮助农民 John 确定锯出这N根木头的最小总花费。 FJ 知道可以有很多种不同的切割方式,不同的方式可能得到不同的总花费,这是因为木头在锯的过程中的长度不一。
输入描述:
Line 1: 一个整数 N,表示要锯出的木头数
Lines 2..N+1: 每行一个整数,表示每根木头的长度。
输出描述:
Line 1: 一个整数,表示他最少需要多少分钱,锯N-1下,锯出所有需要的木头。


示例1
输入

3
8
5
8
输出

34
说明
他需要从总长度为 21 的木头中锯出三根长度分别是 8, 5和8的木头。
原本的木头长度为 8+5+8=21。第一次锯的花费是 21,应该切成两段长度分别是13和8。第二次花费是13,把长度是13的木头锯成8和5。总花费是21+13=34。但如果先将21锯成16和5,第二次将花费16,导致总花费达到37 (大于34)。

分析:

应该是每次把它分成两份(有种二分的思想),但不是完全相等的两份,而是在能刚好切出目标木板的前提下,能分成的最接近的两份。比如目标木板是4,5,6,7四块,就能先分成11和7,(10和8不可能,9和9也不可能,所以最两个最接近的只有11和7了),然后再将11分成5和6,7分成3和4。(仔细想想也不难理解)

上述分析是逆向分析,下面正向分析:

要使上述成立,每次使队列弹出最小的两个,再将这两个的和放入队列中(此时会自动排序),

重复上述步骤,直到队列中只剩一个元素,这个元素就是木板的总长度。

每一步的两个最小元素的和构成了总的最小花费,将它们都加起来就行。

代码:

#include<stdio.h>
#include<queue>
#include<iostream>
using namespace std;
int main()
{
	int n;
	long long sum;
	cin>>n;
	priority_queue<int,vector<int>, greater<int> >Q;
	int temp;
	for(int i=1;i<=n;i++)
	{
		cin>>temp;
		Q.push(temp);
	}
	sum=0;
	int a,b;
	while(Q.size()>1) 
	{
		a=Q.top();
		cout<<a<<endl;
		Q.pop();
		b=Q.top();
		cout<<b<<endl;
		Q.pop(); 
		Q.push(a+b);
		sum+=a+b;
		cout<<sum<<endl;
	}
	cout<<sum<<endl;
	return 0; 
}

 

 

 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嗯嗯你说的对

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值