题目大意
一开始有很多堆果子,合并两堆果子需要数目之和的力气,新的堆加入到果子堆里,直到最后剩余最后一堆。问怎样使用力气和最小。
解题思路
很明显的贪心思想,先挑小的合并。主要使用什么样的数据结构来存储每次加入新堆再合适位置,也就是大小关系。一开始我还想用set,因为set有这有序的天然优势,可是set不能存储相同的值,被pass掉,那到底有没有一种可以存储自带顺序的结构呢?有的,一开始愚蠢没想到,那就是优先队列:
priority_queue<int,vector<int>, greater<int> > q;
那这道题基本就解决了,那要是这样,我肯定不写这篇题解了。这里介绍下本题引申的优先队列和其他做法。
代码展示
#include<bits/stdc++.h>
using namespace std;
priority_queue<int,vector<int>,greater<int> > q;
int main()
{
int n;
cin>>n;
int num;
for(int i=0;i<n;i++) cin>>num,q.push(num);
long long sum=0;
while(q.size()!=1){
int a1=q.top();q.pop();
int a2=q.top();q.pop();
sum+=a1+a2;q.push(a1+a2);
}
cout<<sum<<endl;
return 0;
}
STL之优先队列
队列是一种先进先出的数据结构,元素在队尾加入,从队头弹出。而优先队列,元素被赋予优先级。优先队列具有最高级先出的特点。
下面介绍优先队列常用操作和自定义比较。
1.优先队列的常用操作
q.empty() //如果队列为空返回true,否则返回false
q.size() //返回队列元素个数
q.pop() //删除队首元素,没有返回值
q.top() //返回队首元素
q.push(item) //在基于优先级的适当位置插入
2.优先队列常用定义和重载运算符方法
1. 默认优先级:
#include<queue>
using namespace std;
priority_queue<int>q;
通过<操作符元素大优先级高,从大到小.
2. 传入比较函数,头文件需包括functional.
#include <queue>
#include <functional>
using namespace std;
priority_queue<int, vector<int>, greater<int> > q;
此时从小到大.
3.传入比较结构体,自定义优先级.
#include <queue>
using namespace std;
struct cmp{
bool operator ()(int a,int b){ //通过传入不同类型来定义不同类型优先级
return a>b; //最小值优先
}
};
/**
struct cmp{
bool operator ()(int a,int b){
return a<b; //最大值优先
}
};
**/
priority_queue<int, vector<int>, cmp > q;
4. 传入比较结构体,自定义优先级
#include <queue>
using namespace std;
struct node {
int priority;
int value;
friend bool operator < (const node &a, const node &b) {
return a.priority < b.priority;
}
/* 这样写也可以
bool operator < (const node &a) const {
return priority < a.priority;
}
*/
};
/**
因为标准库默认使用元素类型的<操作符来确定它们之间的优先级关系。而且自定义类型的<操作符与>操作符并无直接联系,故会编译不过。
struct node {
int priority;
int value;
friend bool operator > (const node &a, const node &b) { //错误示范
return a.priority > b.priority;
}
};
**/
priority_queue<node> q;
参考链接
其他结构
堆,小根堆:
- 若树根结点存在左孩子,则根结点的值(或某个域的值)小于等于左孩子结点的值(或某个域的值);
- 若树根结点存在右孩子,则根结点的值(或某个域的值)小于等于右孩子结点的值(或某个域的值);
- 以左、右孩子为根的子树又各是一个堆。
类模板,模板的类型参数由关键字class 或关键字typename 及其后的标识符构成。在模板参数表中关键字class 和typename 的意义相同。(在标准C++之前关键字typename 没有被支持 ,把这个关键字加入到C++中的原因是因为有时必须要靠它来指导编译器解释模板定义。),是对一批仅仅成员数据类型不同的类的抽象,程序员只要为这一批类所组成的整个类家族创建一个类模板,给出一套程序代码,就可以用来生成多种具体的类,(这类可以看作是类模板的实例),从而大大提高编程的效率。————360百科
1. 小根堆模板
#include<cstring>
template<typename item>
class smallest_heap{
private:
item heap[10001];
int len;
public:
smallest_heap();
void push(item const &);
void pop();
item top();
int size();
bool empty();
};
template<typename item>
smallest_heap<item>::smallest_heap(){
len=0;
memset(heap,0,sizeof(heap));
}
template<typename item>
void smallest_heap<item>::push(item const &n){
heap[++len]=n;
int son=len,father=son/2;
while(heap[son]<heap[father] && father>=1){
swap(heap[son],heap[father]);
son=father,father=son/2;
}
}
template<typename item>
void smallest_heap<item>::pop(){
swap(heap[1],heap[len]);
heap[len--]=0;
int father=1,son=2;
while(son<=len){
if(son<len && heap[son]>heap[son+1]) son++;
if(heap[father]>heap[son]){
swap(heap[father],heap[son]);
father=son,son=father*2;
}else break;
}
}
template<typename item>
item smallest_heap<item>::top(){
return heap[1];
}
template<typename item>
int smallest_heap<item>::size(){
return len;
}
template<typename item>
bool smallest_heap<item>::empty(){
return len;
}
2. 大根堆模板
#include<cstring>
template<typename item>
class largest_heap{
private:
item heap[10001];
int len;
public:
largest_heap();
void push(item const &);
void pop();
item top();
int size();
bool empty();
};
template<typename item>
largest_heap<item>::largest_heap(){
len=0;
memset(heap,0,sizeof(heap));
}
template<typename item>
void largest_heap<item>::push(item const &n){
heap[++len]=n;
int son=len,father=son/2;
while(heap[son]>heap[father] && father>=1){
swap(heap[son],heap[father]);
son=father,father=son/2;
}
}
template<typename item>
void largest_heap<item>::pop(){
swap(heap[1],heap[len]);
heap[len--]=0;
int father=1,son=2;
while(son<=len){
if(son<len && heap[son]<heap[son+1]) son++;
if(heap[father]<heap[son]){
swap(heap[father],heap[son]);
father=son,son=father*2;
}else break;
}
}
template<typename item>
item largest_heap<item>::top(){
return heap[1];
}
template<typename item>
int largest_heap<item>::size(){
return len;
}
template<typename item>
bool largest_heap<item>::empty(){
return len;
甚至可以重载<运算符。
class T{
private:
int a;
public:
bool operator<(T const &type){
return a<type.a;
}
};
smallest_heap<T> heap;
附上代码
#include<iostream>
#include<cstring>
using namespace std;
template<typename item>
class smallest_heap{
private:
item heap[10001];
int len;
public:
smallest_heap();
void push(item const &);
void pop();
item top();
int size();
bool empty();
};
template<typename item>
smallest_heap<item>::smallest_heap(){
len=0;
memset(heap,0,sizeof(heap));
}
template<typename item>
void smallest_heap<item>::push(item const &n){
heap[++len]=n;
int son=len,father=son/2;
while(heap[son]<heap[father] && father>=1){
swap(heap[son],heap[father]);
son=father,father=son/2;
}
}
template<typename item>
void smallest_heap<item>::pop(){
swap(heap[1],heap[len]);
heap[len--]=0;
int father=1,son=2;
while(son<=len){
if(son<len && heap[son]>heap[son+1]) son++;
if(heap[father]>heap[son]){
swap(heap[father],heap[son]);
father=son,son=father*2;
}else break;
}
}
template<typename item>
item smallest_heap<item>::top(){
return heap[1];
}
template<typename item>
int smallest_heap<item>::size(){
return len;
}
template<typename item>
bool smallest_heap<item>::empty(){
return len;
}
smallest_heap<int> h;
int n,ans;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
int a;
cin>>a;
h.push(a);
}
while(h.size()>1){
int x=h.top(); h.pop();
int y=h.top(); h.pop();
h.push(x+y);
ans+=x+y;
}
cout<<ans;
return 0;
}