优先队列

本文介绍了优先队列数据结构及其在C++中的实现,通过一个实例展示了如何利用优先队列解决竞赛评分优化问题。在每次比赛中,优先队列用于选择Rating最小的账号参赛,以最大化总Rating之和。代码示例中,利用了C++的`<queue>`和`<vector>`库,以及`greater`比较器实现升序优先队列。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

优先队列

一、定义

普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除。在优先队列中,元素被赋予优先级。当访问元素时,具有最高优先级的元素最先删除。优先队列具有最高级先出 (first in, largest out)的行为特征。通常采用堆数据结构来实现。即优先队列就为可在插入数后进行自动排序的队列。

二、定义

头文件:

#include <queue>
#include <vector>

定义:

priority_queue <int, vector<int>, greater<int> > q;//定义q为整形升序队列;
priority_queue <int, vector<int> > q;//定义q为整形降序队列;

三、基本操作

1、判空

队列名.empty()//返回值是空,为假时非空  

2、求队列中实际元素的个数

队列名.size()

3、入队,入队操作前判断队列是否已满

队列名.push(x)  

4、出队,出队操作前判断队列是否为空

队列名.pop()  

5、取队首元素

队列名.front()  

6、去队尾元素

队列名.back()  

四、经典题目

Rating

一、题目

题目描述

小 L 有 n 个 CF 号,每场比赛他会使用一个账号,会得到一个 Performance,假设原 Rating 为 x,Performance 为 y,则 Rating 变为 x+y2{x+y\over 2}2x+y
小 L 会贪心地选择自己每一次使用的号,使得 每场之后 CF Rating 之和最大,请您在每一场比赛之后输出他的 Rating 之和,保留两位小数。
换句话说,每场之前,小 L 根据当前自己所有号 Rating,选出一个号参加比赛,以最大化这场之后他的 Rating 之和。下一场时,之前的选择都会被保留,即使换一种选择可能使下一场后 Rating 和更大,也不能更换之前的选择。

输入格式

第一行两个正整数 n,m,表示号的个数和比赛场数。
接下来一行 n 个整数,表示他每个号的 Rating。
之后 m 行,每行 1 个整数,表示小 L 的 Performance。

输出格式

对于每一个询问,输出一个实数表示答案,保留两位小数。

样例

输入

5 5
2000 2100 2200 2300 2350
1900
1500
2200
2700
2000

输出

10900.00
10675.00
10912.50
11281.25
11231.25
数据范围与提示

对于 30% 的数据 $ n, m \leq 3 $ 。
对于 60% 的数据 $ n, m \leq 10^3 $ 。
对于另外 20% 的数据,m = 1 。
对于 100% 的数据,$ 1 \leq n, m \leq 10^5 $ , Rating 和 Performance 均为 $ 1 $ ~ $ 10^5 $ 之间的整数。

二、分析

思路:

此题运用优先队列,每一次用n个号中Rating的最小值参加比赛,假设原 Rating 为 x,Performance 为 y,则所损失的分数为x−y2{x-y\over 2}2xy

三、代码

#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
priority_queue <double, vector<double>, greater<double> > q;
int n, m;
double x, ans, r, tot, p;
int main() {
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; i++) {
		scanf("%lf", &x);
		ans += x;
		q.push(x);
	}
	for (int i = 1; i <= m; i++) {
		scanf("%lf", &r);
		tot = (q.top() - r) / 2;
		p = (q.top() + r) / 2;
		ans -= tot;
		q.pop();
		q.push(p);
		printf("%.2lf\n", ans);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值