优先队列

优先队列(priority queue)
普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除。在优先队列中,元素被赋予优先级。当访问元素时,具有最高优先级的元素最先删除。优先队列具有最高级先出 (first in, largest out)的行为特征。通常采用堆数据结构来实现。//摘自百度百科

简单的来说,优先队列作为一个容器,保证按照规定的顺序,最‘大’的元素优先删除。(这里的大是广义的,其实是按你自己定义的排序出队的)
优先队列支持的操作有
1.top();
2.push();
3.pop();

那么在c++中怎么定义优先队列呢?
1.一般方法

priority_queue<int>q;//默认让元素按照从大到小的顺序出队
priority_queue<int,vector<int>, greater<int> >q;//让元素按照从小到大的顺序出队

2.还可以自定义优先级

struct cmp {     
  operator bool ()(int x, int y)     
  {        
     return x > y; // x小的优先级高,小的先出队
  }
};
priority_queue<int, vector<int>, cmp>q;    //定义方法
//其中,第二个参数为容器类型。第三个参数为比较函数。

3.结构体

struct node {     
  int x, y;     
  friend bool operator < (node a, node b)     
  {         
    return a.x > b.x;    //在结构体中,参数x小的优先级高     
  }
};

在ACM中经常会利用优先队列来解决问题。
下面给出一个比较经典的题目
库特的绳子
库特的屋子里有n个钉子,这n个钉子在一条直线上。我们可以把他们看成是数轴上的点,在位置x[i],每个钉子的位置各不相同。现在库特有m条绳子,库特想把所有的绳子都挂在这些钉子间(绳子能挂在两个钉子中间当且仅当两个钉子之间的距离小于等于绳子的长度),库特又不想把两个或以上绳子挂在相同的两个钉子对之间(也就是说任何两个钉子对之间最多只能挂一条绳子),请问库特最后能否将所有的绳子都挂在这些钉子间?

Time Limit:2000ms Memory Limit:65535K
Input

第一行两个整数n和m(2<=n<=5e5,1<=m<=5e5)
第二行n个整数表示n个钉子所在的位置x[1]~x[n] (0<=x[1]<x[2]<…<x[n]<=1e9)
第三行m个整数表示m条绳子的长度a[1]~a[m] (1<=a[i]<=1e9)

Output

如果能,输出yes 否则输出no

Sample Input
3 3
1 2 3
1 2 1
3 3
1 3 5
3 3 3
Sample Output
yes
no

这道题我们很容易想到将钉子的距离找出来,按从小到大的顺序排序,然后将绳子的长度从小到大排序,将绳子与钉子的距离一个对应一个进行比较,若绳子的长度皆大于等于钉子的距离,就输出yes,否则输出no。如果暴力的找钉子的距离,时间复杂度是O(n^2)的,肯定超时,所以我们就想怎么能更少的查找钉子的距离呢。
首先,我们可以知道第i个钉子到第i+1个钉子的距离是一定小于第i个钉子到第i+2个钉子的距离的,而第i个钉子到第i+2个钉子距离是一定小于第i个钉子到第i+3个钉子的距离的,以此类推,我们可以先找第i个钉子到第i+1个钉子的距离去和绳子比较。当然,第i个钉子到第i+k个钉子的距离可能大于第j个钉子到第j+k+1个钉子的距离。这时我们就要利用优先队列将所有第i个钉子到第i+1个钉子的距离放入优先队列中(距离最小先删除)先找到第一小的钉子距离,然后将这个钉子距离的r+1(即将右边的钉子移动到下一个),把这个时候的距离加进优先队列中,这样就保证每次都能找到最小的,复杂度是O(m);
以下是AC代码

#include <bits/stdc++.h>

using namespace std;
struct node
{
    int l,r,s;
};
bool operator < (const node &s1,const node &s2)
{
    return s1.s>s2.s;
}
priority_queue <node>q;
const int MAXN=5e5+5;
int a[MAXN];
int sum[MAXN];
int ma[MAXN];
int b[MAXN];
int main()
{

    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    cin>>a[i];
    for(int i=2;i<=n;i++)
    q.push({i-1,i,a[i]-a[i-1]});
    for(int i=1;i<=m;i++)
    cin>>b[i];
     bool flag=false;
    for(int i=1;i<=m;i++)
    {
        if(q.empty())
        {
            flag=1;
            break;
        }
        struct node temp=q.top();
        q.pop();
        ma[i]=temp.s;
        if(temp.r+1<=n)
        q.push({temp.l,temp.r+1,temp.s+a[temp.r+1]-a[temp.r]});
    }
    sort(b+1,b+1+m);
    if(!flag)
    for(int i=1;i<=m;i++)
    {
        if(b[i]<ma[i])
        {
            flag=1;
            break;
        }
    }
    if(!flag)
    puts("yes");
    else
    puts("no");
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值