0-1分数规划的Dinkelbach算法

来源:互联网 发布:mac终端连接阿里云 编辑:程序博客网 时间:2024/06/02 11:39

基本模型的概述

0-1分数规划问题是经济统计,数据挖掘中一类十分重要的问题.其基本的模型是,我们知道一组产品的投入a[n],也知道一组产品的可以得到的利润,那么,这个时候我们从这n件产品中选择k件,怎么样来选择才能让我们最终的选择利润率最高呢?即我们知道是sigma(b[i])/sigma(a[i])最大

模型的分析

很显然,我们知道,选择b[i]/a[i]最大的k件物品是无法找到最大的组合的,这个定理早已得到证明.那么我们怎么构造才能得到最大值呢?为此,我们设F(L)=sigma(b[i])-L*sigma(a[i]).此时,我们构造一个数组x[i],代表我们是否选择i产品.那么我们的问题又化为了求F(L)=sigma(x[i]*D[i])(D[i]=b[i]-L*a[i])容易知道,如果存在一个组合使得F(L)>0,那么我们可以知道有一个更加优越的组合,此时我们更新L,采用新的组合继续计算.如果我们计算出来的组合与上一次计算出来的组合相同,那么我们知道,Fmax=0.没有比此更好的组合了.这个组合即为最好的组合。
而要计算出来最优的组合,即为计算出F(L)的最大值即可。

计算0-1分数规划的Dinkelbach算法

该算法的伪代码如下所示:
Algorithm Dinkelbach(double L){    for i=1 ~n       g[i]= a[i]-L*a[i]       vis[i]=false //开始时均未被选择    for i=1 ~k       for i=1 ~n          check each to choose the best ans       vis[index]=1;//标记已经选择过的产品}

OJ专题:POJ 2976 Droping tests

即为计算最大的平均分,简单利用Dinkelbach算法迭代计算即可
#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#define K 1010#define INF 0x3f3f3f3fusing namespace std;int a[K],b[K],n,k;double dinkelbach(double L){         double g[K], suma,sumb , minu;         bool vis[K] ;         int i , j , index;         memset(vis,false,sizeof(vis));         suma = sumb =0;         for(i = 1; i <=n ;i++)g[i] = a[i] - L*b[i];         for(i = 1;i <=n-k ; i++)         {               minu = -INF;                for(j = 1;j <=n ;j++)                {                       if(!vis[j]&&g[j] >minu)                       {                               index = j;                               minu = g[j];                       }                }                vis[index] = true;                suma+=a[index];sumb+=b[index];            }            return suma/sumb;}int main(){        int i;        while(scanf("%d %d",&n,&k)!=EOF)        {                if(!n && !k)break;                for(i = 1;i <=n ; i++)cin >> a[i];                for(i = 1;i <=n ; i++)cin >> b[i];                double L1,L2;                L1=0;                while(1)                {                        L2=dinkelbach(L1);                        if(L1 == L2)break;                        L1=L2;                }                printf("%.0lf\n",L1*100);        }        return 0;}



0 0
原创粉丝点击