【POJ 2010 Moo University-Financial Aid】优先级队列
题目链接:http://poj.org/problem?id=2010
题意:C只牛犊,各有自己的分数score和申请的补助aid,现要选出N只(N为奇数),使得其aid的总和不超过F,且按score排序后中位数最大。
数据范围:N [1, 19999], C [N, 10^5], aid [0, 10^5], F, score不超过int的最大值
思路:
1. 先将C只牛按score从小到大排序,得到序列 s,这样顺序抽取出N只构成的序列 t 必然是 s 的子序列。
中位数特殊的地方在于它在序列中所处的位置,t 的长度为N,则中位数 m 是 t 的第N/2个位置(从0开始数),因此从原序列中抽取时,要保证 m 前后都已有N/2个元素。
所以 m 的位置在原序列中是有一定范围约束的,具体分析可得范围区间[N/2, C-N/2-1](从0开始)。
2. 既然已经按score从小到大排序,那么我们希望 m 在原序列 s 中的位置越靠后越好。因此可以在范围区间内从后往前枚举中位数的位置 i,判断以 i 为中位数能否选出aid总和不超过F的子序列 t。
3. 枚举的区间长度为O(C-N*2)=O(C), 每个枚举位置的判断若为O(C)一定超时。好在只是求中位数的值,不必找出所有解,甚至不必维护解,那么可以用贪心策略构造一个aid总和尽可能小的解,若其值满足条件,则说明必然有解。
4. 如何得到贪心策略的值呢,接下来的做法是参考了网上别人的思路:
预处理出两个数组before[i], after[i],分别记录位置 i 前、后按贪心策略选出的N/2个元素所能得到的最小aid总和。
具体先对 s 序列从左到右扫描,用容量上限为N/2的大顶堆维护当前扫描位置 i 之前的aid值最小的N/2个元素,并把堆中元素值总和记录在数组元素before[i]中。
然后再进行一遍从右到左的扫描,填充数组after[i]。
这里为了减少预处理的的时间,我只对before数组进行了预处理,after数组可以随着枚举位置的移动而计算,这样一旦枚举到一个可行位置,则不必计算剩余的after[i]。
这个堆开始写搓了。。。上滤下滤忘加else break了一直T,对基本原理的掌握还是不够熟练啊
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAX_C = ; int heap[MAX_C]; void swap(int& a, int& b){
int tmp = a;
a = b;
b = tmp;
} struct Heap
{
int heap[MAX_C];//大顶堆
int size;
Heap(){size=;}
void insert(int x){
size++;
heap[size-] = x;
int i = size - ;
while(i > ){
int p = (i-)/;
if(heap[p] < heap[i]){
swap(heap[p], heap[i]);
i = p;
}else break;
}
}
int getTop(){
return heap[];
}
void deleteTop(){
heap[] = heap[size-];
size--;
int i = ;
while(i*+ < size){
int lc = i*+, rc=i*+;
int c = lc;
if(rc<size && heap[rc]>heap[lc])
c = rc;
if(heap[c] > heap[i]){
swap(heap[c], heap[i]);
i = c;
}else break;
}
}
}; struct Calf
{
int score, aid;
}calves[MAX_C];
bool cmp(Calf c1, Calf c2){
return c1.score < c2.score;
} int N, C, F;
int before[MAX_C], after[MAX_C]; int main()
{
freopen("2010.txt", "r", stdin);
scanf("%d%d%d", &N, &C, &F);
for(int i=; i<C; i++){
scanf("%d%d", &calves[i].score, &calves[i].aid);
}
int begin = N/;
int end = C-N/-;
sort(calves, calves+C, cmp); if(N==){
printf("%d\n", calves[C-].score);
return ;
} Heap hb; //前begin的before[i]=0
memset(before, , sizeof(before));
memset(after, , sizeof(after)); //printf("begin=%d\nend=%d\n", begin, end);
for(int i=; i<begin; i++){ //N为奇数,begin为中间数
hb.insert(calves[i].aid);
before[begin] += calves[i].aid;//前begin个必然算入before[begin]
}
//第begin个开始有对换
for(int i=begin+; i<=end; i++){
if(calves[i-].aid < hb.getTop()){//有比堆顶更小的aid,对换
before[i] = before[i-] - hb.getTop() + calves[i-].aid;
hb.deleteTop();
hb.insert(calves[i-].aid);
}else before[i] = before[i-];
} Heap ha;
for(int i=C-; i>end; i--){
ha.insert(calves[i].aid);
after[end] += calves[i].aid;//后begin个必然算入after[C-begin]
}
//printf("after[%d] = %d\n", end, after[end]);
int flag = -;
int sum = calves[end].aid + before[end] + after[end];
if(sum <= F){
printf("%d\n", calves[end].score);
return ;
}
for(int i=end-; i>=begin; i--){ //开始从后往前枚举中位数i
if(calves[i+].aid < ha.getTop()){
after[i] = after[i+] - ha.getTop() + calves[i+].aid;
ha.deleteTop();
ha.insert(calves[i+].aid);
}else after[i] = after[i+];
//printf("after %d: %d\n", i, after[i]);
int sum = before[i] + after[i] + calves[i].aid;
//printf("sum %d: %d\n", i, sum);
if(sum <= F){
flag = calves[i].score;
break;
}
}
printf("%d\n", flag);
return ;
}
【POJ 2010 Moo University-Financial Aid】优先级队列的更多相关文章
- POJ 2010 Moo University - Financial Aid( 优先队列+二分查找)
POJ 2010 Moo University - Financial Aid 题目大意,从C头申请读书的牛中选出N头,这N头牛的需要的额外学费之和不能超过F,并且要使得这N头牛的中位数最大.若不存在 ...
- poj 2010 Moo University - Financial Aid
Moo Univ ...
- poj 2010 Moo University - Financial Aid 最大化中位数 二分搜索 以后需要慢慢体会
Moo University - Financial Aid Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 6599 A ...
- poj -2010 Moo University - Financial Aid (优先队列)
http://poj.org/problem?id=2010 "Moo U"大学有一种非常严格的入学考试(CSAT) ,每头小牛都会有一个得分.然而,"Moo U&quo ...
- poj 2010 Moo University - Financial Aid(优先队列(最小堆)+ 贪心 + 枚举)
Description Bessie noted that although humans have many universities they can attend, cows have none ...
- POJ 2010 - Moo University - Financial Aid 初探数据结构 二叉堆
考虑到数据结构短板严重,从计算几何换换口味= = 二叉堆 简介 堆总保持每个节点小于(大于)父亲节点.这样的堆被称作大根堆(小根堆). 顾名思义,大根堆的数根是堆内的最大元素. 堆的意义在于能快速O( ...
- poj 2010 Moo University - Financial Aid (贪心+线段树)
转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove 骗一下访问量.... 题意大概是:从c个中选出n个 ...
- POJ 2010 Moo University - Financial Aid(堆维护滑窗kth,二分)
按照score排序,贪心,从左到右用堆维护并且记录前面的最小N/2个花费之和. 然后从右向左枚举中位数,维护N/2个数之和加上并判断是否满足条件.(stl的队列没有clear(),只能一个一个pop. ...
- POJ 2010 Moo University - Financial Aid treap
按第一关键字排序后枚举中位数,就变成了判断“左边前K小的和 + 这个中位数 + 右边前K小的和 <= F",其中维护前K小和可以用treap做到. #include <cstdi ...
- POJ 2010 Moo University - Financial Aid 优先队列
题意:给你c头牛,并给出每头牛的分数和花费,要求你找出其中n(n为奇数)头牛,并使这n头牛的分数的中位数尽可能大,同时这n头牛的总花费不能超过f,否则输出-1. 思路:首先对n头牛按分数进行排序,然后 ...
随机推荐
- Maximum Subarray / Best Time To Buy And Sell Stock 与 prefixNum
这两个系列的题目其实是同一套题,可以互相转换. 首先我们定义一个数组: prefixSum (前序和数组) Given nums: [1, 2, -2, 3] prefixSum: [0, 1, 3, ...
- Animation Override Controller动画重载器
假设游戏有很多个小人, 每一个人有2种动画站立,跑. 在通常情况下每一个人物都需要一个动画控制器. 有没有想过定义一个动画控制器 无须在定义全新的动画充值器实现每一个小人都播放自己的动画呢?没错An ...
- UIButton-初识IOS
今天,我学到了所有app经常用到的UIButton控件,废话不多说,这些都是我学习的时候总结的一些,希望可以帮到以后的初学者,IOS初学不应该直接拖拽,感觉不易于理解,所以我总结的基本上全是纯代码编辑 ...
- rhel5.8-LAMP环境搭建
一.LAMP安装前的准备 安装环境:rhel5.8 zabbix-2.4.5 php-5.6.8 MySQL5.6.23 libpng-1.5.9 zlib-1.2.7 (apr,apr ...
- gcc基本用法
GCC基本用法 GCC最基本的用法是: gcc [option] filenames option:编译器所需要的编译选项 filenames:要编译的文件名 gcc编译流程 都以 hello.c 为 ...
- C#中DataGridView控件使用大全
DataGridView 动态添加新行: DataGridView控件在实际应用中非常实用,特别需要表格显示数据时.可以静态绑定数据源,这样就自动为DataGridView控件添加相应的行.假如需要动 ...
- EasyuiCombobox三级联动
有许多刚接触Easyui中Combobox控件的朋友可能都会遇到的问题:如何将Combobox做成三级联动? 先本人有个三级联动的案例给大家参考参考,经测试能通过.注意Combobox绑定的数据是Js ...
- Eclipse控制台显示Tomcat日志
今天看一篇学习Struts的博文,文章里面提到从生成的日志,结果,怎么鼓捣都看不到.心情也跟着烦躁了.于是晚饭后出去散步,冷静一下,然后决定晚上一定搞掂这个问题.这不,搞掂了,写篇博文记录一下. St ...
- PHP APC缓存配置、使用详解
一.APC缓存简介 APC,全称是Alternative PHP Cache,官方翻译叫”可选PHP缓存”.它为我们提供了缓存和优化PHP的中间代码的框架. APC的缓存分两部分:系统缓存和用户数据缓 ...
- Unity3d Web Player 的server端联网配置
新游戏出了第一个能跑完流程的版本,不得不佩服Unity3D强大的功力,PC.MAC OS.Linux.IOS.Android.web player,前天刚发布的unity3d 4.2版本还支持WIND ...