优先队列
一、优先队列简单介绍
- 优先队列是一种数据结构,能够实现插入一个数值,并且取出最小值(最大值)并删除等操作。
- 能够使用某种二叉树来实现优先队列,这种二叉树叫“堆”。堆分为小根堆和大根堆,小根堆的意思就是所有的子节点值一定不比父亲的值小,大根堆就是所有的子节点值一定不比父亲的节点值大。并且向堆中插入和取最小的值(或最大)的值得复杂度都为
O(logn)
。
二、STL中的优先队列
都要加头文件 #include<queue>
,具体参考https://www.cnblogs.com/flyoung2008/articles/2136485.html
- 默认大根堆,
priority_queue<int > q;
。 - 小根堆,
priority_queue<int, vector<int>, greater<int> > q;
- 自定义数据结构:
priority_queue<Node> q;
,要重写operator<
,
bool operator<(Node a, Node b){
if(a.x == b.x) return a.y > b.y;
return a.x > b.x; //大于则小根堆,小于则大根堆
}
三、例题 POJ2431 Expedition
题目链接http://poj.org/problem?id=2431
题意:
驾驶卡车行驶L单位距离,卡车初始P单位汽油,行驶1单位距离消耗1单位汽油。图中有一些加油站,可以在加油站中给汽车加油,知道加油站离终点的距离也知道每个加油站最多给汽车加多少油,现在要求最少停车几次,能够使得汽车到达终点。若不能到达,输出-1。
思路:
- 题目中加油站数量N非常大,所以不能暴力。然后可以这样想,路过加油站的时候,先不加油,但是你没油的时候你要知道你之前是可以加油的。也就是到达加油站的时候,就获得了加油的权利。这样,当汽车没油的时候,认为在之前加过油就行了。
- 那么为了使得加油次数最少,每次没油的时候就选取经过的加油站中能够加油最多的一个加油站加油即可。那么就用到了优先队列,大根堆。路过时push(),加油时pop()。
AC代码
#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn = 10010;
struct Node{
int x;
int y;
}stop[maxn];
bool cmp (Node a, Node b) //按照距离从大到小排序
{
return a.x > b.x;
}
int main()
{
int n, l, p, cnt = 0;;
scanf("%d",&n);
priority_queue<int > q;
for(int i = 0; i < n ;i ++){
scanf("%d%d", &stop[i].x, &stop[i].y);
}
scanf("%d%d", &l, &p);
sort(stop, stop + n, cmp);
int i = 0;
p ++; //防止初始位置就有加油站
l ++;
while(p != 0 && l != 0){
p --;
l --;
//cout<<"p="<<p<<" l="<<l<<endl;
if(l == 0) //到达终点
break;
if(i < n && stop[i].x == l){ //路过加油站
q.push(stop[i++].y);
}
if(p == 0 && q.size() != 0){ //没油了 并且还可以加油
p += q.top();
q.pop();
cnt ++; //停车次数加1
}
}
if(l == 0){
printf("%d\n",cnt);
} else {
printf("-1\n");
}
return 0;
}