1. 程式人生 > >藍書(演算法競賽進階指南)刷題記錄——POJ2976 Dropping tests(0-1分數規劃)

藍書(演算法競賽進階指南)刷題記錄——POJ2976 Dropping tests(0-1分數規劃)

題目:POJ2976.

題目大意:給定你n組a_i,b_i,讓你取出n-k組,使得這n-k組的a之和除以b之和最大.

這是一個經典的0-1分數規劃模型.

關於0-1分數規劃模型,一般就是確定一個標準值mid,發現:

\sum_{i=1}^{n}(a_i-mid*b_i)*x_i\geq 0,那麼\sum_{i=1}^{n}a_i*x_i-mid*\sum_{i=1}^{n}b_i*x_i\geq 0,也就是說\sum_{i=1}^{n}\frac{a_i}{b_i}*x_i\geq mid.

同理,若\sum_{i=1}^{n}(a_i-mid*b_i)*x_i< 0,就是\sum_{i=1}^{n}\frac{a_i}{b_i}*x_i< mid.

突然發現這個東西滿足二分性質.

所以我們就可以二分mid,然後判定這個式子的最大值是否會大於0.

判定的話找到最大的n-k組(a_i-mid*b_i),算一下和,判斷和是否大於等於0即可.

程式碼如下:

#include<iostream>
#include<cstdio>
#include<map>
#include<algorithm>
  using namespace std;
#define Abigail inline void
typedef long long LL;
const double eps=1e-8;
const int N=1000;
int n,k;
double c[N+9],a[N+9],b[N+9];
double l,r,mid;
double check(double mid){
  double sum=0.0;
  for (int i=1;i<=n;i++)
    c[i]=a[i]-mid*b[i];
  sort(c+1,c+1+n);
  for (int i=n;i>k;i--)
    sum+=c[i];
  return sum;
}
Abigail into(){
  for (int i=1;i<=n;i++) scanf("%lf",&a[i]);
  for (int i=1;i<=n;i++) scanf("%lf",&b[i]);
}
Abigail work(){
  l=0;r=1;
  while (l+eps<r){
    mid=(l+r)/2.0;
    if (check(mid)>0) l=mid;
    else r=mid;
  }
}
Abigail outo(){
  printf("%.0lf\n",100*r);
}
int main(){
  while (scanf("%d%d",&n,&k),n+k){
    into();
    work();
    outo();
  }
  return 0;
}

為什麼在POJ上用編譯器選G++掛了,C++就過了...

貌似C++輸出double需要%lf,G++上需要%f.