一.定义
优先队列(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 31 8 5
9 2 5
10 7 6
样例输出:
9 10 12
四.暴力枚举(O())
解法比较简单,把所以情况都加一下存入数组,再排序即可
但数据为k<=750,即循环次数为,显然会超时。
五.思路:
我们不妨这样想一想,每行有n个数,要求前k个数。我们可以先把每一行数据升序排序,再把第一行前k个数加上第二行前k个数,会得到2k个数据,在这2k个数中再排序前k个数就是矩阵为2行的ans;之后再把这k个数存入第二行中与第三行加,再重复步骤。就可以得到矩阵为3行的ans了。这样数据就只需要算遍了,时间复杂度由O()降到O(n^2)。
六.建模:
我们再每次计算之后都要把数据再排序,取前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;
}