• poj2010 Moo University


                            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
    ",maxscore);
        }
        return 0;
    }
    
    

      



     

    

  • 相关阅读:
    BZOJ 2157: 旅游 (2017.7.21 6:30-2017.7.21 15:38 今日第一题。。)
    洛谷 P1021 邮票面值设计
    洛谷 P2912 [USACO08OCT]牧场散步Pasture Walking
    COGS 2111. [NOIP2015普及]扫雷游戏
    洛谷 P3038 [USACO11DEC]牧草种植Grass Planting
    COGS 1439. [NOIP2013]货车运输
    COGS 908. 校园网
    codevs 1422 河城荷取
    codevs 1183 泥泞的道路
    洛谷 P3390 【模板】矩阵快速幂
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/5208915.html
Copyright © 2020-2023  润新知