POJO 2010 -- Moo University - Financial Aid


http://poj.org/problem?id=2010
Description
Bessie noted that although humans have many universities they can attend, cows have none. To remedy this problem, she and her fellow cows formed a new university called The University of Wisconsin-Farmside,"Moo U" for short.

Not wishing to admit dumber-than-average cows, the founders created an incredibly precise admission exam called the Cow Scholastic Aptitude Test (CSAT) that yields scores in the range 1..2,000,000,000.

Moo U is very expensive to attend; not all calves can afford it.In fact, most calves need some sort of financial aid (0 <= aid <=100,000). The government does not provide scholarships to calves,so all the money must come from the university's limited fund (whose total money is F, 0 <= F <= 2,000,000,000).

Worse still, Moo U only has classrooms for an odd number N (1 <= N <= 19,999) of the C (N <= C <= 100,000) calves who have applied.Bessie wants to admit exactly N calves in order to maximize educational opportunity. She still wants the median CSAT score of the admitted calves to be as high as possible.

Recall that the median of a set of integers whose size is odd is the middle value when they are sorted. For example, the median of the set {3, 8, 9, 7, 5} is 7, as there are exactly two values above 7 and exactly two values below it.

Given the score and required financial aid for each calf that applies, the total number of calves to accept, and the total amount of money Bessie has for financial aid, determine the maximum median score Bessie can obtain by carefully admitting an optimal set of calves.
Input
* Line 1: Three space-separated integers N, C, and F

* Lines 2..C+1: Two space-separated integers per line. The first is the calf's CSAT score; the second integer is the required amount of financial aid the calf needs 
Output
* Line 1: A single integer, the maximum median score that Bessie can achieve. If there is insufficient money to admit N calves,output -1. 
Sample Input
3 5 70
30 25
50 21
20 20
5 18
35 30
Sample Output
35
http://www.hankcs.com/program/cpp/poj-2010-moo-university-financial-aid.html
奶牛大学:奶大招生,从C头奶牛中招收N头。它们分别得分score_i,需要资助学费aid_i。希望新生所需资助不超过F,同时得分中位数最高。求此中位数。
题意:奶牛学校招生,要录取n(奇数)个学生,报名了c个学生,每个学生有成绩s_i和需要的补助金f_i。学校的补助金一共为F元,挑选n个学生,f_1+f_2+f_i+....+f_n不得大于n,且n个奶牛的s_i的中位数最大,输出这个数?
最朴素的办法:按分数从小到大排列,枚举原点,从右到左扫,区间为[(m+1)/2,n-(m+1)/2],计算左边最小和和右边最小和,判断是否是满足条件,满足即输出。
显然这种n2的办法是不行的。
我们要减复杂度,就要在枚举原点的同时维护左右两边最小和,如何维护?

X. 
优先队列+枚举,分治解法:
将奶牛按照成绩s_i从小到大排序,从 n/2 到 m-1-n/2枚举中位数,记录每个i的前面n/2数的f之和,和后面n/2数的f之后,然后枚举满足条件最大的中位数。
https://blog.csdn.net/liuke19950717/article/details/51057360
在保证中位数最大的情况下,如何保证正好取N个!
    DP的话数据量太大,搜索也搜不动,贪心很难保证恰好取N个。


    根据 sorce递增排序, 枚举中位数a[i]! 那么肯定在 [1,i-1]区间内取N/2个数, 在 [i+1,C]内取N/2个数!


    问题就转化为: 求分别求区间 [1,i-1]、[i+1,C]中N/2个数的最小值。  N/2+1<=i<=C-N/2
    这时需要一个高效的数据结构!
    我们来维护一个 大小为 N/2的最大堆。
    例如对于区间 [1,i-1],  初始堆为 [1,N/2], sum= sum([1,N/2].aid)  (aid为所需资助)
    每次拓展区间长度时,我们只需比较新扩展的结点(key)与 堆顶元素(fro)的大小。 if (key<fro) 则弹出堆顶元素,并且使 key入堆,并更新 sum。(保证和最小!)
  区间[i+1,C]也是一样。
    最后倒序枚举中位数即可。


最大堆
2.4 加工并储存数据的数据结构
优先队列
先将奶牛排序,考虑每个奶牛作为中位数时,比它分数低(前面的)的那群牛的学费总和lower_i,后面的总和upper_i。然后从分数高往分数低扫描,满足aid_i + lower_i + upper_i <= F的第一个解就是最优解。
相比于这种“枚举”,还有一种利用二分搜索的快速实现:http://www.hankcs.com/program/cpp/poj-2010-moo-university-financial-aid-binary-search.html
#define MAX_COW 100000 + 16
int N, C, F;
pair<intint> cow[MAX_COW];
// 牛i作为中位数时,lower[i]表示分数低于它的牛的学费总和
int lower[MAX_COW], upper[MAX_COW];
///////////////////////////SubMain//////////////////////////////////
int main(int argc, char *argv[])
{
#ifndef ONLINE_JUDGE
    freopen("in.txt""r", stdin);
    freopen("out.txt""w", stdout);
#endif
    cin >> N >> C >> F;
    int half = N / 2;
    for (int i = 0; i < C; ++i)
    {
        cin >> cow[i].first >> cow[i].second;   // 分数 <-> 学费
    }
    sort(cow, cow + C);
    {
        int total = 0;
        priority_queue<int> q;
        for (int i = 0; i < C; ++i)
        {
            lower[i] = q.size() == half ? total : 0x3f3f3f3f;
            q.push(cow[i].second);
            total += cow[i].second;
            if (q.size() > half)
            {
                // 然后踢掉一个学费最高的家伙
                total -= q.top(); q.pop();
            }
        }
    }
    {
        int total = 0;
        priority_queue<int> q;
        for (int i = C - 1; i >= 0; --i)
        {
            upper[i] = q.size() == half ? total : 0x3f3f3f3f;
            q.push(cow[i].second);
            total += cow[i].second;
            if (q.size() > half)
            {
                // 然后踢掉一个学费最高的家伙
                total -= q.top(); q.pop();
            }
        }
    }
    int result;
    for (int i = C - 1; i >= 0; --i)
    {
        if (lower[i] + cow[i].second + upper[i] <= F)
        {
            result = cow[i].first;
            break;
        }
    }
    cout << result << endl;
     
#ifndef ONLINE_JUDGE
    fclose(stdin);
    fclose(stdout);
    system("out.txt");
#endif
    return 0;
}

struct node
{
int num,val;
}x[maxn];
int cmp(node a,node b)
{
if(a.num==b.num)
{
return a.val<b.val;
}
return a.num<b.num;
}
int lower[maxn],upper[maxn];
int slove(int n,int m,int s)
{
memset(lower,-1,sizeof(lower));
memset(upper,-1,sizeof(upper));
sort(x,x+n,cmp);
int mid=m/2,cnta=0,cntb=0;
priority_queue<int> qa;
priority_queue<int> qb;
for(int i=0;i<n;++i)
{
lower[i]=(qa.size()==mid)?cnta:inf;
upper[n-i-1]=(qb.size()==mid)?cntb:inf;
qa.push(x[i].val);
qb.push(x[n-i-1].val);
cnta+=x[i].val;
cntb+=x[n-i-1].val;
if(qa.size()>mid)
{
cnta-=qa.top();
qa.pop();
}
if(qb.size()>mid)
{
cntb-=qb.top();
qb.pop();
}
}
for(int i=n-1;i>=0;--i)
{
if(lower[i]+x[i].val<=s-upper[i])
{
return x[i].num;
}
}
return -1;
}

X. Bisection
http://www.hankcs.com/program/cpp/poj-2010-moo-university-financial-aid-binary-search.html
现在用二分再做一遍。在分别排序分数和学费之后,以分数为界限将牛分为左右两个区间,统计左区间符合条件的数目left和右区间的数目right。讨论left 和right是否满足条件。以此为基础二分,实际上下面的谓词逻辑可以优化,但是目前看起来比较好懂。

分别用分数和所需补助金给奶牛排序,用分数为界限将奶牛分为左右两区间两部分,再分别查找左区间满足条件的奶牛数 left  和右区间满足条件的奶牛数 right。  讨论 left 和 right 的值分情况取讨论如何修改下一次要查找的值。

  1. int N, C, F;
  2. int lower[MAX_COW], upper[MAX_COW];
  3. struct Cow
  4. {
  5. int rank_by_score, score, aid;
  6. };
  7. Cow cow_score[MAX_COW], cow_aid[MAX_COW];
  8. bool less_by_score(Cow& a, Cow& b)
  9. {
  10. return a.score < b.score;
  11. }
  12. bool less_by_aid(Cow& a, Cow& b)
  13. {
  14. return a.aid < b.aid;
  15. }
  16.  
  17. ///////////////////////////SubMain//////////////////////////////////
  18. int main(int argc, char *argv[])
  19. {
  20. #ifndef ONLINE_JUDGE
  21. freopen("in.txt", "r", stdin);
  22. freopen("out.txt", "w", stdout);
  23. #endif
  24. ios::sync_with_stdio(false);
  25. cin.tie(0);
  26. cin >> N >> C >> F;
  27. int half = N / 2;
  28. for (int i = 0; i < C; ++i)
  29. {
  30. cin >> cow_score[i].score >> cow_score[i].aid;   // 分数  学费
  31. }
  32. sort(cow_score, cow_score + C, less_by_score);
  33. for (int i = 0; i < C; ++i)
  34. {
  35. cow_score[i].rank_by_score = i;
  36. }
  37. memcpy(cow_aid, cow_score, sizeof(Cow) * C);
  38. sort(cow_aid, cow_aid + C, less_by_aid);
  39.  
  40. int lb = 0, ub = C, ans = -1;
  41. while (ub - lb > 1)
  42. {
  43. int mid = (ub + lb) >> 1;
  44. // 将牛分为左右两个区间,统计左区间符合条件的数目left和右区间的数目right
  45. // 情况比较多,总体是二分,实际上有四种情况
  46. int left = 0, right = 0, total_aid = cow_score[mid].aid;
  47. for (int i = 0; i < C; ++i)
  48. {
  49. if ((cow_aid[i].rank_by_score < mid) && (total_aid + cow_aid[i].aid <= F) && (left < N / 2))
  50. {
  51. total_aid += cow_aid[i].aid;
  52. ++left;
  53. }
  54. else if ((cow_aid[i].rank_by_score > mid) && (total_aid + cow_aid[i].aid <= F) && (right < N / 2))
  55. {
  56. total_aid += cow_aid[i].aid;
  57. ++right;
  58. }
  59. }
  60. // 四种情况
  61. if ((left < N / 2) && (right < N / 2))
  62. {
  63. ans = -1;
  64. break;
  65. }
  66. else if (left < N / 2)
  67. {
  68. lb = mid;
  69. }
  70. else if (right < N / 2)
  71. {
  72. ub = mid;
  73. }
  74. else
  75. {
  76. ans = cow_score[mid].score;
  77. lb = mid;
  78. }
  79. }
  80. cout << ans << endl;
Read full article from 2010 -- Moo University - Financial Aid

Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts