优先队列/堆 题目讲解

优先队列/堆 题目讲解

cpp 复制代码
洛谷
P1628
p1334
p1090
p12802
p2278

priority_queue(优先队列/堆)
cpp 复制代码
//大根堆
priority_queue<int> heap;

//小根堆
priority_queue<int,vector<int>,greater<int>> heap;

heap.push(x);//插入一个数x
heap.top();//返回堆顶元素
heap.pop();//弹出堆顶元素

pq.emplace(people[j].r, people[j].idx);等效于pq.push(make_pair(people[j].r, people[j].idx));
在优先队列 pq 中,直接构造一个 pair(r, idx) 对象,

p1628

小根堆读入符合要求的字符串然后依次读,弹就行

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int n;
    cin>>n;

    vector<string> a(n);
    for(int i = 0;i<n;i++) cin>>a[i];

    string T;
    cin>>T;

    priority_queue<string,vector<string>,greater<string>> q;

    for(int i = 0;i<n;i++){
        if(a[i].size()>=T.size() && a[i].substr(0,T.size())==T){
            q.push(a[i]);
        }
    }

    while(!q.empty()){
        cout<<q.top()<<"\n";
        q.pop();
    }
}

p1334

倒过来看,等价于不断合并两块木板,合并代价是两块之和,得到代价总和最小,那就贪心思想每次取最小两块合并。同样可以用小根堆解决。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int n;
    cin>>n;

    priority_queue<ll,vector<ll>,greater<ll>> q;

    for(int i = 0;i<n;i++){
        ll x;
        cin>>x;
        q.push(x);
    }

    ll ans = 0;

    while(q.size()>1){
        ll a = q.top(); q.pop();
        ll b = q.top(); q.pop();
        ll s = a+b;
        ans += s;
        q.push(s);
    }

    cout<<ans;
}

p1090

这题与上一题本质完美一模一样,甚至代码都不用改的。就是上一题倒过来的思维

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int n;
    cin>>n;

    priority_queue<ll,vector<ll>,greater<ll>> q;

    for(int i = 0;i<n;i++){
        ll x;
        cin>>x;
        q.push(x);
    }

    ll ans = 0;

    while(q.size()>1){
        ll a = q.top(); q.pop();
        ll b = q.top(); q.pop();
        ll s = a+b;
        ans += s;
        q.push(s);
    }

    cout<<ans;
}

p12802

也是贪心加优先队列,对于入侵的,肯定优先入侵好打的(人少的)。贪心优先入侵小星球积累资源,再用大根堆动员最大舰队以最少次数征服剩余星球。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int T;
    cin>>T;

    while(T--){
        int n;
        ll k;
        cin>>n>>k;

        vector<ll>a(n);
        ll sum = 0;
        for(int i = 0;i<n;i++){
            cin>>a[i];
            sum += a[i];
        }

        if(k>=sum){
            cout<<0<<"\n";
            continue;
        }

        sort(a.begin(),a.end());

        priority_queue<ll> q;

        ll temp = 0;
        ll ans = 0;
        int p = 0;

        while(1){

            while(p<n && a[p]<=k+temp){
                q.push(a[p]);
                p++;
            }

            if(q.empty()){
                cout<<-1<<"\n";
                break;
            }

            temp += q.top();
            q.pop();
            ans++;

            if(k+2*temp>=sum){
                cout<<ans<<"\n";
                break;
            }
        }
    }
}

p2278

优先队列+臭模拟,跟前面的不同之处在于要自定义一下priority_queue的排序规则

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

struct node{
	int id,st,re,pr;
	bool operator < (const node &a)const{
		if(pr==a.pr) return st>a.st;   // 优先级相同,先到的优先
		else return pr<a.pr;          // 优先级大的优先
	}
};

node c;
long long ti;                     // 当前时间
priority_queue<node> q;           // 等待队列(大根堆)

int main(){
	while(cin>>c.id>>c.st>>c.re>>c.pr){
		
		// 先把当前能在新进程到达前执行完的进程全部跑完
		while(!q.empty() && ti+q.top().re<=c.st){
			node b=q.top(); q.pop();
			cout<<b.id<<" "<<ti+b.re<<endl;  // 输出完成时间
			ti+=b.re;                       // 时间推进
		}
		
		// 若当前进程还没跑完,被新进程抢占
		if(!q.empty()){
			node d=q.top(); q.pop();
			d.re=d.re-(c.st-ti);   // 减去已经执行的时间
			q.push(d);             // 放回等待队列
		}
		
		q.push(c);     // 新进程入队
		ti=c.st;       // 时间跳到新进程到达时刻
	}
	
	// 输入结束后,把剩余进程全部跑完
	while(!q.empty()){
		node f=q.top(); q.pop();
		ti+=f.re;
		cout<<f.id<<" "<<ti<<endl;
	}
	return 0;
}
相关推荐
半生过往5 小时前
前端工程师学习智能体开发(一)
前端·学习·状态模式
荆棘鸟智能5 小时前
无人机遥感图像实时拼接算法工程实践:从特征提取到全景融合的完整技术链路
算法·无人机
6Hzlia6 小时前
【Classic 150 刷题计划】 LeetCode 58. 最后一个单词的长度 | C++ 极简反向遍历与单变量状态机
算法
AgentMaster6 小时前
企业如何应用智能客服?5 个典型场景的技术架构与实施路径
大数据·算法
程曦曦6 小时前
MySQL 生产库误删 98 张表后的时间点恢复实战:从 binlog 解析到资金对账
linux·数据结构·其他·算法·ubuntu·运维开发
weixin_307779137 小时前
C++代码实现MATLAB中的ode45函数功能
开发语言·c++·算法·matlab
m4Rk_7 小时前
【论文阅读】Agent 记忆机制(67):MemPO——用记忆级信用分配训练 Agent 主动管理长程上下文
论文阅读·人工智能·学习·开源·github
不穿鞋的懒羊羊7 小时前
dfs深度优先搜索
算法
下辈子不要当码农7 小时前
ARM学习(1)
学习·arm
OYYHXPJR8 小时前
【算法】区间重叠模板和矩形重叠模板
算法