01分数规划

01分数规划问题:所谓的01分数规划问题就是指这样的一类问题,给定两个数组,a[i]表示选取i的收益,b[i]表示选取i的代价。如果选取i,定义x[i]=1否则x[i]=0。每一个物品只有选或者不选两种方案,求一个选择方案使得R=sigma(a[i]*x[i])/sigma(b[i]*x[i])取得最值,(sigma为累加符号),即所有选择物品的总收益/总代价的值最大或是最小。

01分数规划问题主要包含一般的01分数规划、最优比率生成树问题、最优比率环问题等。我们将会对这三个问题进行讨论。

我们的目标是使R取到最值,本文主要讨论取到最大值的情况。

我们先定义一个函数F(L) = sigma(a[i]*x[i])-L*sigma(b[i]*x[i]),显然这只是对目标式的一个简单的变形。分离参数,得到

F(L) = sigma((a[i]-L*b[i])*x[i])。这时我们就会发现,如果L已知的话,a[i]-L*b[i]就是已知的,当然x[i]是未知的。记d[i]=a[i]-L*b[i],那么F(L) = sigma(d[i]*x[i])。这个函数,它与目标式的关系非常的密切,L就是目标式中的R,最大化R也就是最大化L。

F的值是由两个变量共同决定的,即方案X和参数L。对于一个确定的参数L来说,方案的不同会导致对应的F值的不同。

假设我们已知在存在一个方案X使得F(L) > 0

F(L) = sigma(a[i]*x[i])-L*sigma(b[i]*x[i]) > 0即sigma(a[i]*x[i])/sigma(b[i]*x[i]) > L也就是说,如果一个方案使得F(L)>0说明了这组方案可以得到一个比现在的L更优的一个L,既然有一个更优的解,那么为什么不用呢?

显然,d数组是随着L的增大而单调减的。也就是说,存在一个临界的L使得不存在一种方案,能够使F(L)>0. 我们猜想,这个时候的L就是我们要求的最优解。之后更大的L值则会造成无论任何一种方案,都会使F(L)<0.类似于上面的那个变形,我们知道,F(L)<0是没有意义的,因为这时候的L是不能够被取得的。当F(L) = 0 时,对应方案的R值恰好等于此时的L值。

 综上,函数F(L)有这样的一个性质:在前一段L中可以找到一组对应的X使得F(L)>0,这就提供了一种证据,即有一个比现在的L更优的解,而在某个L值使,存在一组解使得F(L)=0,且其他的F(L)<0,这时的L无法继续增大,即这个L就是我们期望的最优解,之后的L会使得无论哪种方案都会造成F(L)<0.而我们已经知道,F(L)<0是没有任何意义的,因为此时的L值根本取不到。


2018年东北农业大学春季校赛

I-why的物品


#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

const double inf = 1e-6;
double a[100010];
double b[100010];
double f[100010];

int binary(double x,int n,int k)
{
    for(int i = 0; i < n; i++)
    {
        f[i] = b[i]-x*a[i];
    }
    sort(f, f+n);
    double ans = 0;
    for(int i = n-1; i > n-1-k; i--)
        ans += f[i];
    if(ans >= 0)
        return 1;
    return 0;
}

int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        int n, k ;
        cin >> n >> k;
        memset(a, 0, sizeof(a));
        memset(b, 0, sizeof(b));
        memset(f, 0, sizeof(f));
 
        double maxx = 0;
        for(int i = 0; i < n; i++)
        {
            scanf("%lf%lf", &a[i], &b[i]);
            maxx = max(maxx,b[i]/a[i]);
        }
 	double l = 0;
        double r = maxx;
        while(r-l > inf)
        {
            double mid = (r+l)/2;
            if(binary(mid,n,k))
                l = mid;
            else
                r = mid;
        }
        printf("%.2lf\n",r);
        
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/qq_38295645/article/details/80303771