【POJ 2010 Moo University-Financial Aid】优先级队列
2016-05-13 14:56
519 查看
题目链接: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,对基本原理的掌握还是不够熟练啊
题意: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 = 100005; 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=0;} void insert(int x){ size++; heap[size-1] = x; int i = size - 1; while(i > 0){ int p = (i-1)/2; if(heap[p] < heap[i]){ swap(heap[p], heap[i]); i = p; }else break; } } int getTop(){ return heap[0]; } void deleteTop(){ heap[0] = heap[size-1]; size--; int i = 0; while(i*2+1 < size){ int lc = i*2+1, rc=i*2+2; 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=0; i<C; i++){ scanf("%d%d", &calves[i].score, &calves[i].aid); } int begin = N/2; int end = C-N/2-1; sort(calves, calves+C, cmp); if(N==1){ printf("%d\n", calves[C-1].score); return 0; } Heap hb; //前begin的before[i]=0 memset(before, 0, sizeof(before)); memset(after, 0, sizeof(after)); //printf("begin=%d\nend=%d\n", begin, end); for(int i=0; i<begin; i++){ //N为奇数,begin为中间数 hb.insert(calves[i].aid); before[begin] += calves[i].aid;//前begin个必然算入before[begin] } //第begin个开始有对换 for(int i=begin+1; i<=end; i++){ if(calves[i-1].aid < hb.getTop()){//有比堆顶更小的aid,对换 before[i] = before[i-1] - hb.getTop() + calves[i-1].aid; hb.deleteTop(); hb.insert(calves[i-1].aid); }else before[i] = before[i-1]; } Heap ha; for(int i=C-1; 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 = -1; int sum = calves[end].aid + before[end] + after[end]; if(sum <= F){ printf("%d\n", calves[end].score); return 0; } for(int i=end-1; i>=begin; i--){ //开始从后往前枚举中位数i if(calves[i+1].aid < ha.getTop()){ after[i] = after[i+1] - ha.getTop() + calves[i+1].aid; ha.deleteTop(); ha.insert(calves[i+1].aid); }else after[i] = after[i+1]; //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 0; }
相关文章推荐
- matplotlib InstallationError: Command python setup.py egg_info failed with error code 1
- pair类型
- 人工智能过去60年沉浮史,未来60年将彻底改变人类
- int main(int argc,char* argv[])浅析
- 问题:connect() failed (111: Connection refused) while connecting to upstream
- kail2.0下hping3的安装和使用(二)
- 利用wait()和notify()实现生产者与消费者问题
- Selenium - Waits
- airdrop分享, Sender kSFOperationEventErrorOccured {
- Determining IP information for eth0... failed; no link present. Check cable?
- IIC 读写时候提示 timeout waiting for bus ready
- 2011版MacBook Air win7安装教程
- 查看当前的git用户名以及email
- failed to obtain a cell from its dataSource 解决方案
- poj1681Painter's Problem 增广矩阵消元法错误水过版
- http://blog.csdn.net/ta893115871/article/details/46955791/
- 【华为OJ】【054-Redraiment的走法】
- UVa - 514 Rails(栈模拟)
- UVa - 442 Matrix Chain Multiplication(栈模拟)
- TurboMail邮件系统资深技术支持杨工专访(二)