【队列】优先队列

一.定义

优先队列(Priority Queue)是一种特殊的队列,其中每个元素都带有一个优先级。优先级最高的元素最先被取出。如果两个元素具有相同的优先级,则它们按照它们在队列中的顺序被取出。

优先队列可以使用不同的数据结构实现,例如堆、二叉搜索树或有序数组。其中,是实现优先队列最常用的数据结构,因为它具有良好的时间复杂度和空间复杂度。

二.函数的调用

默认为降序优先队列:priority_queue<int> q;

降序优先队列:priority_queue<int,vector<int>,less<int> >q1;

升序优先队列:priority_queue<int,vector<int>,greater<int> >q2;

注意:最后两个尖括号要空一格(<int> >)

***优先队列是用堆实现的,所以要用栈的应用方式(eg:s.pop();s.top())***

三.经典例题

题目描述:

给定一个n*n的一个矩阵,如果让你在每一行取出一个数再将每一行取出的数相加,那么总共可以得到n^n种相加方法,现在让你求出这n^n个结果中最小的k个结果(n<=750)

样例输入:
3 3

1 8 5

9 2 5

10 7 6

样例输出:
9 10 12

四.暴力枚举(O(n^{n}))

 解法比较简单,把所以情况都加一下存入数组,再排序即可

但数据为k<=750,即循环次数为750^{750},显然会超时。

五.思路:

我们不妨这样想一想,每行有n个数,要求前k个数。我们可以先把每一行数据升序排序,再把第一行前k个数加上第二行前k个数,会得到2k个数据,在这2k个数中再排序前k个数就是矩阵为2行的ans;之后再把这k个数存入第二行中与第三行加,再重复步骤。就可以得到矩阵为3行的ans了。这样数据就只需要算k^{k}遍了,时间复杂度由O(n^{n})降到O(n^2\log k)。

六.建模:

我们再每次计算之后都要把数据再排序,取前k个数保存。想到这里,我们不妨使用优先队列来维护数据的升序。所以,这道题我们选择了优先队列。

七.【AC】代码+注释

#include<bits/stdc++.h>
using namespace std;
int a[1001][1001]; //定义二维数组,用于存储矩阵
priority_queue<int,vector<int>,greater<int> >q1; //定义小根堆,用于存储每个元素与下一行所有元素的和
int main(){
    int n,u;
    cin>>n>>u; //读入矩阵的大小
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            cin>>a[i][j]; //读入矩阵中的元素
        }
        sort(a[i]+1,a[i]+n+1); //对第i行的元素进行升序排序
    }
    for(int i=1;i<=n;i++){ //枚举每一行
        for(int j=1;j<=u;j++){ //枚举当前行的元素
            for(int k=1;k<=u;k++){ //枚举下一行的元素
                q1.push(a[i][j]+a[i+1][k]); //计算当前元素和下一行元素的和,并将和存入小根堆中
            }
        }
        for(int k=1;k<=u;k++){ //取出小根堆中的前n个元素,作为下一行的候选元素
            a[i+1][k]=q1.top();
            q1.pop();
        }
        while(!q1.empty()){ //清空小根堆中剩余的元素
            q1.pop();
        }
    }
    for(int i=1;i<=u;i++){ //输出最后一行中的元素,即为所求的升序序列
        cout<<a[n][i]<<" ";
    }
    return 0;
}


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值