蓝书(算法竞赛进阶指南)刷题记录——POJ2976 Dropping tests(0-1分数规划)

版权声明:转载请注明原出处啦QAQ(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/83140747

题目: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.

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/83140747
今日推荐