poj2010 Moo University - Financial Aid
Moo University - Financial Aid
题意:
一个私立学校的学生要申请奖学金,而学校的金额有限。因此,学校希望在金额不超过F的情况下从C中选得N对数。
给出三个数N,C,F。分别代表在C对数中要取得N对数。
而每对数分别代表成绩,跟申请金额。要求取得N对数中的总金额不超过F的条件下,然取得中间的以为学生的成绩最高。(N为even)
算法分析:
本题有两种解法,一种是用优先队列,一种是二分;
一、利用堆实现
先说堆的实现方法,我们能够现对头尾的N/2进行处理,由于头尾的N/2个数一定不可能成为中位数即答案。然后,在左右扫描记录当前的最小金额。
最后,在两边夹逼得出最大中位数。
怎样处理左右扫描呢?
我以头为例(尾的扫描也一样),先得到队列中一个最大的金额。跟当前的比較假设比当前的大,则更新之。这样队列就会始终保持这在当前成绩之前的N/2个最小的金额。尾一个道理。最后用头尾相加得到最大值。
二、二分实现
二分的还是比較好想到的,就是对题目要求的答案进行二分。
这里先对成绩排序然后二分。
然而这题的二分返回值有点特殊。
详细细节请看代码.
堆实现版:
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> using namespace std; const int MAXN = 100000 + 20; struct Node{ int score,aid,id; }; int N,C,F; Node cow_score[MAXN],cow_aid[MAXN]; bool cmp_score(const Node& a,const Node& b){ return a.score < b.score; } bool cmp_aid(const Node& a,const Node& b){ return a.aid < b.aid; } int main() { cin >> N >> C >> F; for(int i = 0;i < C;++i){ cin >> cow_score[i].score >> cow_score[i].aid; } sort(cow_score,cow_score + C,cmp_score); for(int i = 0;i < C;++i){ cow_score[i].id = i; } memcpy(cow_aid,cow_score,sizeof(Node) * C); sort(cow_aid,cow_aid + C,cmp_aid); int ans = -1,lb = 0,ub = C; while(ub - lb > 1){ int mid = (ub + lb) >> 1; int lft = 0,rht = 0,sum = cow_score[mid].aid; for(int i = 0;i < C;++i){ if((cow_aid[i].id < mid)&&(sum + cow_aid[i].aid <= F)&&(lft < N / 2)){ sum += cow_aid[i].aid; ++lft; } else if((cow_aid[i].id > mid)&&(sum + cow_aid[i].aid <= F)&&(rht < N / 2)){ sum += cow_aid[i].aid; ++rht; } } if((lft < N / 2)&&(rht < N / 2)){ ans = -1; break; } else if(lft < N / 2){ lb = mid; } else if(rht < N / 2){ ub = mid; } else{ ans = cow_score[mid].score; lb = mid; } } cout << ans << endl; return 0; }
二分实现版:
#include <iostream> #include <algorithm> #include <queue> #include <cstdio> using namespace std; const int MAXN = 100000 + 10; int N,F,C; struct Cow_score{ int score,aid,rval,lval; Cow_score():rval(0),lval(0){}; bool operator < (const Cow_score& rhs)const{ //排序score return score < rhs.score; } }; struct Cmp_score{ //排序aid bool operator()(Cow_score a,Cow_score b){ return a.aid < b.aid; } }; Cow_score cow[MAXN]; int main() { while(~scanf("%d%d%d",&N,&C,&F)){ N /= 2; for(int i = 0;i < C;++i){ scanf("%d%d",&cow[i].score,&cow[i].aid); } sort(cow,cow + C); priority_queue<Cow_score,vector<Cow_score>,Cmp_score> left_aid; priority_queue<Cow_score,vector<Cow_score>,Cmp_score> right_aid; Cow_score tmp; int sumaid = 0; for(int i = 0;i < N;++i){ sumaid += cow[i].aid; left_aid.push(cow[i]); } for(int i = N;i < C - N;++i){ // 枚举左边 cow[i].lval = sumaid; tmp = left_aid.top(); if(tmp.aid > cow[i].aid){ left_aid.pop(); left_aid.push(cow[i]); sumaid = sumaid - tmp.aid + cow[i].aid; } } sumaid = 0; for(int i = C - N;i < C;++i){ sumaid += cow[i].aid; right_aid.push(cow[i]); } for(int i = C-N-1;i >= N;--i){ //枚举右边 cow[i].rval = sumaid; tmp = right_aid.top(); if(tmp.aid > cow[i].aid){ right_aid.pop(); right_aid.push(cow[i]); sumaid = sumaid - tmp.aid + cow[i].aid; } } int maxscore = -1; for(int i = N;i < C - N;++i){ //夹中间 if(cow[i].lval + cow[i].rval + cow[i].aid <= F&&maxscore < cow[i].score){ maxscore = cow[i].score; } } printf("%d\n",maxscore); } return 0; }