2018-07-17

优先队列,即Priority Queues

1.简单介绍一下队列(介绍功能,不作分析)

C++队列是一种容器适配器,它给予程序员一种先进先出(FIFO)的数据结构。

back() 返回最后一个元素
empty() 如果队列空则返回真
front() 返回第一个元素
pop() 删除第一个元素
push() 在末尾加入一个元素
size() 返回队列中元素的个数


2.双向队列deque

deque双向队列是一种双向开口的连续线性空间,可以高效的在头尾两端插入和删除元素,deque在接口上和vector非常相似。
目前使用双向队列是在做“窗口最大/小值”类型的题才用到。平常使用较少。

assign() 设置双向队列的值
at() 返回指定的元素
back() 返回最后一个元素
begin() 返回指向第一个元素的迭代器
clear() 删除所有元素
empty() 返回真如果双向队列为空
end() 返回指向尾部的迭代器
erase() 删除一个元素
front() 返回第一个元素
get_allocator() 返回双向队列的配置器
insert() 插入一个元素到双向队列中
max_size() 返回双向队列能容纳的最大元素个数
pop_back() 删除尾部的元素
pop_front() 删除头部的元素
push_back() 在尾部加入一个元素
push_front() 在头部加入一个元素
rbegin() 返回指向尾部的逆向迭代器
rend() 返回指向头部的逆向迭代器
resize() 改变双向队列的大小
size() 返回双向队列中元素的个数
swap() 和另一个双向队列交换元素


3.Priority Queues(优先队列)

C++优先队列类似队列,但是在这个数据结构中的元素按照一定的断言排列有序。

empty() 如果优先队列为空,则返回真
pop() 删除第一个元素
push() 加入一个元素
size() 返回优先队列中拥有的元素的个数
top() 返回优先队列中有最高优先级的元素

优先级队列可以用向量(vector)或双向队列(deque)来实现(注意list container 不能用来实现queue,因为list 的迭代器不是任意存取iterator,而pop 中用到堆排序时是要求randomaccess iterator 的):

priority_queue<int> pq1; // 使用递增less<int>函数对象排序,大顶堆 priority_queue<int,vector<int>, greater<int> > pq2; // 使用递减greater<int>函数对象排序,小顶堆

(建议包含头文件<functional>,因为有些oj需要)

4.优先队列的模板题

那么优先队列所实现的大根堆和小根堆有什么用呢?

如果题目要求如下:不停地给你int型整数 即类似如下代码

1 int a;

2 while(cin>>a)

然后要去,如果输入的整数是0,输出目前数组的最大值和最小值,如果a是-1,结束。

这个时候直接用大(小)根堆就可以搞定。

优先队列所实现的大(小)根堆

那好,我们来看一下实例

在UVa 11292 - Dragon of Loowater 问题中,我们可以使用小根堆
题意: 有n个头的恶龙,你雇佣一些骑士把所有的头砍掉,一共有m个骑士可以雇佣, 一个能力为x的骑士只能砍下恶龙一个直径不超过x的头,而且要支付x个金币。
问:如何雇佣骑士才能砍掉所有恶龙的头,而且要使付出的金币最少。
注意:一个骑士只能砍掉一个头,而且只能被雇用一次!
输入为: n m 接下来n行为恶龙的头的直径。 再接下来是m行骑士的能力。 如果不能看下所有恶龙的头,输出: “Loowater is doomed!” 否则输出最少花费


思路:利用2个小根堆,分别存龙和骑士的数值。然后弹出龙和骑士的数值x和y,如果龙x小于等于骑士y,则维护一个sum值。如果龙x大于骑士y,则弹出下一个骑士的数值。

如果龙x的小根堆空了,就输出sum,如果骑士的小根堆先空了,输出“Loowater is doomed!”

附上小根堆ac代码

#include<bits/stdc++.h>

using namespace std;
#define _for(i,a,b) for(int i=a;i<b;++i)
#define _For(i,a,b) for(int i=a;i<=b;++i)
#define for_(i,a,b) for(int i=a;i>b;--i)
#define For_(i,a,b) for(int i=a;i>=b;--i)
#define ll long long
#define mem(a,b) memset(a,b,sizeof a)
#define INF 0x7f7f7f7f
#define inf 0x3f3f3f3f

int main(){  
    int n,m,tmp,x,y;
    while(cin>>n>>m){
        if(n==0&&m==0) break;
        priority_queue<int,vector<int> , greater<int> > dragon; 
        priority_queue<int,vector<int> , greater<int> > knight;
        int cost=0;
        int succeed=0;
        for(int i=0;i<n;i++){
            cin>>tmp;
            dragon.push(tmp);
        } 
        for(int i=0;i<m;i++){
            cin>>tmp;
            knight.push(tmp);
        } 
        while(!knight.empty()){//当还有能力值更高的骑士的时候
            x=dragon.top();//当前最弱小的龙
            y=knight.top();knight.pop();//派当前最弱的骑士,无论屠龙与否,下一次都会派更强的骑士
            if(x<=y){//如果屠龙成功
                cost+=y;//支付报酬 
                dragon.pop();//这条龙没了,出队列 
            }
            if(dragon.empty()){//龙屠干净了 
                cout<<cost<<endl;//输出总费用 
                succeed=1;//成功了 
                break; 
            } 
        } 
        if(!succeed) 
            cout<<"Loowater is doomed!"<<endl; //如果没成功,输出失败 
        } 
    return 0;
}