POJ 2976 Dropping tests


In a certain course, you take n tests. If you get ai out of bi questions correct on test i, your cumulative average is defined to be
.
Given your test scores and a positive integer k, determine how high you can make your cumulative average if you are allowed to drop any k of your test scores.
Suppose you take 3 tests with scores of 5/5, 0/1, and 2/6. Without dropping any tests, your cumulative average is . However, if you drop the third test, your cumulative average becomes .
Input
The input test file will contain multiple test cases, each containing exactly three lines. The first line contains two integers, 1 ≤ n ≤ 1000 and 0 ≤ k < n. The second line contains n integers indicating ai for all i. The third line contains n positive integers indicating bi for all i. It is guaranteed that 0 ≤ ai  bi ≤ 1, 000, 000, 000. The end-of-file is marked by a test case with n = k = 0 and should not be processed

https://github.com/cherryljr/NowCoder/blob/master/POJ-2976%20Dropping%20tests.java
 * 题意:有N个考试,每个考试有ai和bi两个值,最后成绩由上面的公式求得。幸运的是,可以放弃K个科目,求最大化最后的成绩。
 * 思路:该题实质上就是一个 最大化平均值 的问题
 * 最大化平均值:有n个物品的重量和价值分别为 wi 和 vi,从中选择 k 个物品使得单位重量的价值最大。
 * 
 * 那么首先本题需要确定一个贪心策略,来去掉那些对正确率贡献小的考试。
 * 那么如何确定某个考试[ai, bi]对总体准确率x的贡献呢?
 * ai / bi肯定是不行的,不然例子里的[0,1]会首当其冲被刷掉。
 * 因此这里需要使用到 01分数规划 的一个技巧:
 * 题目求的是 max(∑a[i] / ∑b[i]),其中a,b都是一一对应的。
 * 那么可以转化一下:
 *   令 r = ∑a[i] / ∑b[i],则有 ∑a[i] - ∑b[i] * r = 0;
 * 然后我们就可以 二分枚举 r 的值即可。
 * 对于每一个 r, 求出每个 a[i] - b[i] * r; 然后排序,去除 k 个最小值。
 * 然后相加得到结果 Q(r),
 * 如果 Q(r) > 0 说明 r 的值偏小,因为可能存在 r 使得 Q(r) = 0;
 * 如果 Q(r) < 0 说明选取的 r 值过大;
 * 
 * 时间复杂度:O(nlogn)
 * 
 * 类似的问题:
 *  Maximum Average Subarray II: (最大化平均值)
 *  https://github.com/cherryljr/LintCode/blob/master/Maximum%20Average%20Subarray%20II.java
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    while (sc.hasNext()) {
      int n = sc.nextInt(), k = sc.nextInt();
      if (n == 0 && k == 0) {
        break;
      }
      double[] a = new double[n];
      double[] b = new double[n];
      for (int i = 0; i < n; i++) {
        a[i] = sc.nextDouble();
      }
      for (int i = 0; i < n; i++) {
        b[i] = sc.nextDouble();
      }
      System.out.printf("%.0f\n", 100 * binarySearch(a, b, n, k));
    }
  }

  private static double binarySearch(double[] a, double[] b, int n, int k) {
    double min = 0.0, max = 1.0;
    while (Math.abs(max - min) > 1e-6) {
      double mid = (max + min) / 2;
      double[] arr = new double[n];
      for (int i = 0; i < n; i++) {
        arr[i] = a[i] - mid * b[i];
      }
      // Greedy, sort the arr and remove the k smallest elements.
      Arrays.sort(arr);
      double sum = 0;
      for (int i = k; i < n; i++) {
        sum += arr[i];
      }
      if (sum < 0) {
        max = mid;
      } else {
        min = mid;
      }
    }
    return min;
  }

题目大意就 给定n个二元组(a,b),扔掉k个二元组,使得剩下的a元素之和与b元素之和的比率最大,题目求的是 max(∑a[i] * x[i] / (b[i] * x[i]))  
乍看以为贪心或dp能解决,后来发现贪心策略与当前的总体准确率有关,行不通,于是二分解决。
依然需要确定一个贪心策略,每次贪心地去掉那些对正确率贡献小的考试。如何确定某个考试[a_i, b_i]对总体准确率x的贡献呢?a_i / b_i肯定是不行的,不然例子里的[0,1]会首当其冲被刷掉。在当前准确率为x的情况下,这场考试"额外"对的题目数量是a_i � x * b_i,当然这个值有正有负,恰好可以作为"贡献度"的测量。于是利用这个给考试排个降序,后k个刷掉就行了。
int n, k;
double x;  // 搜索过程中的正确率
struct Test
{
    int a, b;
    bool operator < (const Test& other) const
    {
        return a - x * b > other.a - x * other.b; // 按照对准确率的贡献从大到小排序
    }
};
Test test[MAX_N];
// 判断是否能够获得大于mid的准确率
bool C(double mid)
{
    x = mid;
    sort(test, test + n);
    double total_a = 0, total_b = 0;
    for (int i = 0; i < n - k; ++i)                    // 去掉后k个数计算准确率
    {
        total_a += test[i].a;
        total_b += test[i].b;
    }
    return total_a / total_b  > mid;
}
///////////////////////////SubMain//////////////////////////////////
int main(int argc, char *argv[])
{
#ifndef ONLINE_JUDGE
    freopen("in.txt""r", stdin);
    freopen("out.txt""w", stdout);
#endif
    while (cin >> n >> k && (n || k))
    {
        for (int i = 0; i < n; ++i)
        {
            cin >> test[i].a;
        }
        for (int i = 0; i < n; ++i)
        {
            cin >> test[i].b;
        }
        double lb = 0; double ub = 1;
        while (abs(ub - lb) > 1e-4)
        {
            double mid = (lb + ub) / 2;
            if (C(mid))
            {
                lb = mid; // 行,说明mid太小
            }
            else
            {
                ub = mid; // 不行,说明mid太大
            }
        }
        cout << fixed << setprecision(0) << lb * 100 << endl;
    }
#ifndef ONLINE_JUDGE
    fclose(stdin);
    fclose(stdout);
    system("out.txt");
#endif
    return 0;
}
Code from http://www.tuicool.com/articles/En63i2
http://www.tuicool.com/articles/YFjMvu
看解题报告说是 01分数规划搜索,只看懂了解题报告的意思。
题目大意就 给定n个二元组(a,b),扔掉k个二元组,使得剩下的a元素之和与b元素之和的比率最大,以下 是复制自其它人的博客
     题目求的是 max(∑a[i] * x[i] / (b[i] * x[i]))  
    转:那么可以转化一下。  令r = ∑a[i] * x[i] / (b[i] * x[i])  则必然∑a[i] * x[i] - ∑b[i] * x[i] * r= 0;(条件1)
并且任意的 ∑a[i] * x[i] - ∑b[i] * x[i] * max(r) <= 0  (条件2,只有当∑a[i] * x[i] / (b[i] * x[i]) = max(r) 条件2中等号才成立)
     然后就可以枚举r , 对枚举的r, 求Q(r) = ∑a[i] * x[i] - ∑b[i] * x[i] * r  的最大值,  为什么要求最大值呢?  因为我们之前知道了条件2,所以当我们枚举到r为max(r)的值时,显然对于所有的情况Q(r)都会小于等于0,并且Q(r)的最大值一定是0.而我们求最大值的目的就是寻找Q(r)=0的可能性,这样就满足了条件1,最后就是枚举使得Q(r)恰好等于0时就找到了max(r)。而如果能Q(r)&gt;0 说明该r值是偏小的,并且可能存在Q(r)=0,而Q(r)<0的话,很明显是r值偏大的,因为max(r)都是使Q(r)最大值为0,说明不可能存在Q(r)=0了。
double does(double num)
{
  for(int i=0;i<n;i++)
  {
    t[i]=a[i]-num*b[i];
  }
  sort(t,t+n);
  double sum=0.0;
  for(int i=k;i<n;i++)
  {
    sum+=t[i];
  }
  return sum;
}

int main()
{
  while(scanf("%d%d",&n,&k),n||k)
  {
    for(int i=0;i<n;i++)
    {
      scanf("%lf",&a[i]);
    }
    for(int i=0;i<n;i++)
    {
      scanf("%lf",&b[i]);
    }
    double l=0.0,r=1.0,mid;
    while(r-l>eps)
    {
      mid=(l+r)/2;
      if(does(mid)>0)l=mid;
      else r=mid;
    }
    printf("%.0f\n",l*100);
  }
  return 0;
}
X. 01分数规划
https://blog.csdn.net/u013486414/article/details/47398771
Dinkelbach算法求01分数规划:
const int inf=0x3f3f3f3f;
const double pi= acos(-1.0);
const double esp=1e-7;
const int maxn=1010;
int n,k;
struct node
{
    double a,b,d;
}q[maxn];
int cmp(struct node x,struct node y)
{
    return x.d<y.d;
}
double Dinkelbach()
{
    double L,ans=0;
    double x,y;
    while(1){
        L=ans;
        for(int i=0;i<n;i++)
            q[i].d=q[i].a-L*q[i].b;
        sort(q,q+n,cmp);
        x=y=0;
        for(int i=k;i<n;i++){
            x+=q[i].a;
            y+=q[i].b;
        }
        ans=x/y;
        if(fabs(L-ans)<esp) return L;
    }
}
int main()
{
    while(~scanf("%d %d",&n,&k)){
        if(!n&&!k) break;
        for(int i=0;i<n;i++)
            scanf("%lf",&q[i].a);
        for(int i=0;i<n;i++)
            scanf("%lf",&q[i].b);
        printf("%.0f\n",Dinkelbach()*100);
    }
    return 0;
}

Read full article from POJ 2976 Dropping tests 题解 《挑战程序设计竞赛》 � 码农场

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