码迷,mamicode.com
首页 > 其他好文 > 详细

『0/1分数规划 二分法』

时间:2019-04-20 21:06:31      阅读:143      评论:0      收藏:0      [点我收藏+]

标签:模板   ace   opp   枚举   main   const   存在   sample   --   

<更新提示>

<第一次更新>


<正文>

0/1分数规划

模型

0/1分数规划指的是这样一个问题模型:

给定整数\(a_1,a_2,...,a_n\)\(b_1,b_2,...,b_n\),求一组解\(x_1,x_2,...,x_n(\forall\ i\in[1,n],x_i=1,0)\),使得下式最大化:\[\frac{\sum_{i=1}^na_i*x_i}{\sum_{i=1}^nb_i*x_i}\]

简单地说,就是给定\(n\)对整数\(a_i,b_i\),从中选取若干对,使得选出的\(a\)之和与\(b\)之和的比值最大。

二分法

这个问题模型可以使用二分法解决。

不妨二分枚举一个数\(L\),然后考虑是否存在一组解,使得\(\sum_{i=1}^n(a_i-Lb_i)*x_i\geq 0\)

\(1.\) 若存在一组解,使得\(\sum_{i=1}^n(a_i-Lb_i)*x_i\geq 0\),则显然有\(\sum_{i=1}^na_ix_i-L\sum_{i=1}^nb_ix_i\geq 0\),那么就有\[\exists \{x_1,x_2,...,x_n\},\frac{\sum_{i=1}^na_i*x_i}{\sum_{i=1}^nb_i*x_i}\geq L\]

就可以得到最优解一定大于等于\(L\)

\(2.\) 若对于每一组解,都有\(\sum_{i=1}^n(a_i-Lb_i)*x_i< 0\),则同理可知
\[\forall \{x_1,x_2,...,x_n\},\frac{\sum_{i=1}^na_i*x_i}{\sum_{i=1}^nb_i*x_i}< L\]

就可以得到最优解一定不到\(L\)

那么我们就可以依次进行二分答案,最后的结果就是\(L\)

求解形如\(\sum_{i=1}^n(a_i-Lb_i)*x_i\)是否非负的问题是简单的,由于\(a_i-Lb_i\)的值可以直接计算,所以直接取适当的\(x_i\),让上式最大化或最小化即可。

Dropping Test

Description

给定你n组ai,bi,让你取出n?k组,使得这n?k组的a之和除以b之和最大.

Input Format

输入包括多组数据.

每组数据第一行包括两个数n和k,意义如题,若n和k为0表示输入结束.

接下来一行n个数,第i个数表示ai.再接下来一行n个数,第i个数表示bi.

Output Format

对于每组输入数据输出一行一个数表示答案,答案保留整数.

Sample Input

3 1
5 0 2
5 1 6
4 2
1 2 7 9
5 6 7 9
0 0

Sample Output

83
100

解析

\(0/1\)分数规划模板题,直接二分答案,然后暴力排序判定即可。

\(Code:\)

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+20;
const double eps=1e-7;
int n,k,ans;
double a[N],b[N],val[N];
inline void input(void)
{
    for (int i=1;i<=n;i++)
        scanf("%lf",&a[i]);
    for (int i=1;i<=n;i++)
        scanf("%lf",&b[i]);
}
inline double check(double L)
{
    double res = 0.0;
    for (int i=1;i<=n;i++)
        val[i] = a[i] - L * b[i];
    sort( val+1 , val+n+1 );
    for (int i=n;i>=k+1;i--)
        res += val[i];
    return res;
}
inline void fraction_planning(void)
{
    double l=0.0,r=1.0,mid;
    while ( l + eps < r )
    {
        mid = (l+r) / 2;
        if (check(mid)>=0)l=mid;
        else r=mid;
    }
    ans = (int)(mid*100+0.5);
}
int main(void)
{
    while ( scanf("%d%d",&n,&k) && (n|k) )
    {
        input();
        fraction_planning();
        printf("%d\n",ans);
    }
    return 0;
}


<后记>

『0/1分数规划 二分法』

标签:模板   ace   opp   枚举   main   const   存在   sample   --   

原文地址:https://www.cnblogs.com/Parsnip/p/10742572.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!