luogu p1090 合并果子

题目大意

一开始有很多堆果子,合并两堆果子需要数目之和的力气,新的堆加入到果子堆里,直到最后剩余最后一堆。问怎样使用力气和最小。

解题思路

很明显的贪心思想,先挑小的合并。主要使用什么样的数据结构来存储每次加入新堆再合适位置,也就是大小关系。一开始我还想用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;

参考链接

C++ STL优先队列常用用法

其他结构

堆,小根堆:

  1. 若树根结点存在左孩子,则根结点的值(或某个域的值)小于等于左孩子结点的值(或某个域的值);
  2. 若树根结点存在右孩子,则根结点的值(或某个域的值)小于等于右孩子结点的值(或某个域的值);
  3. 以左、右孩子为根的子树又各是一个堆。

类模板,模板的类型参数由关键字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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值