01背包问题的多种求解

1.问题描述

问题描述: 有一个容量为V的背包,还有n个物体。现在忽略物体实际几何形状,我们认为只要背包的剩余容量大于等于物体体积,那就可以装进背包里。每个物体都有两个属性,即体积w和价值v。使物品装入背包的价值最大。

2.0-1背包问题的解决思路

    1.方法一:枚举法,首先想到最简单的枚举法,通过列举所有结果,从中筛选出满足题意的结果。

    2.方法二:回溯法,在枚举法的基础上进行约束剪枝和限界剪枝。
    3.方法三:动态规划,运用动态规划思想,动态规划与分治法类似,都是把大问题拆分成小问题,通过寻找大问题与小问题的递推关系,使用递推算法解决一个个小问题,最终达到解决原问题的效果。

2.3.1、如果装不下当前物品,那么前n个物品的最佳组合和前n-1个物品的最佳组合是一样的。
2.3.2、如果装得下当前物品。
假设1 :装当前物品,在给当前物品预留了相应空间的情况下,前n-1个物品的最佳组合加上当前物品的价值就是总价值。
假设2:不装当前物品,那么前n个物品的最佳组合和前n-1个物品的最佳组合是一样
选取假设1和假设2中较大的价值,为当前最佳组合的价值。

3.问题求解中所遇到的问题及分析解决方案;

问题:枚举法和回溯法运算规模较大、时间较长,动态规划中存在重叠子问题,递归方程多次调用自身使时间复杂度较大,01背包问题无法用贪心算法来解决

解决方案:使用动态规划方法时利用备忘录方法解决重复计算的问题,用递推方程替代递归方程

4问题的解决方案

问题求解关键技术:约束剪枝、限界剪枝、备忘录方法

5.算法测试

在比较枚举法,回溯法,动态规划法完成问题的时间复杂度之后,发现动态规划法是该问题的最优解。通过对01背包问题解法的扩展,可解决完全背包、多重背包等一些问题。

枚举法:#include <stdio.h>

#include <stdlib.h>

#include <time.h>

const int N=10;//全局变量,物品数量

const int bag=N;//全局变量,背包承重量

int max_value=0;//全局变量,记录能获得的最大价值

int backpack(int a[],int v[],int w[],int n,int t)

{

   int max_v=0,max_w=0;//背包累积的最大价值和最大重量

   if(t>n-1)//递归结束的条件

   {

       printf("找到一个方案");

       for(int i=0;i<n;i++){//遍历数组a根据其记录的0、1值进行背包价值和重量计算

          printf("%d",a[i]);

          max_v=max_v+v[i]*a[i];//found!!!!!如何计算max_v

          max_w=max_w+w[i]*a[i];//found!!!!!如何计算max_w

       }

       if(max_w>bag)//found!!!!!根据max_w判断该方案是否超重

          printf("\n该方案总价%d,总重%d,超重!不可行!!!\n",max_v,max_w);

       else{//如果不超重

          if(max_v>max_value)//found!!!!!比较该方案所获得的价值是不是比全局最优解更优

              max_value=max_v;//更新最优解

          printf("\n该方案总价%d,总重%d,可行\n",max_v,max_w);

       }

    }else{

        for(int i=1;i>=0;i--)//只取值1或0

        {

            a[t]=i;//记录当前物品选1或不选0

          backpack(a,v,w,n,t+1);//递归到下一层

        }

    }

   return max_value;//返回最大价值

}

int main()

{

   int a[N],v[N],w[N],i,start,end;

   printf("背包最大承重%d公斤\n",bag);

   for(i=0;i<N;i++)//随机生成价值和重量

   {

       v[i]=rand()%5+1;

       w[i]=rand()%5+1;

       printf("物品%d,价值%d,重量%d\n",i,v[i],w[i]);

   }

   start=clock();

   printf("能获得的最大价值为:%d\n",backpack(a,v,w,N,0));

   end=clock();

   printf("耗时:%dms\n",end-start);

   return 0;

}

1-3枚举法运行结果

回溯法:

int backpack(int t,int now_v,int now_w)

{//t表示递归层数,now_v表示当前层所累积的价值,now_w表示当前层所累积的重量

   int i;

   if(t>N-1)//当递归到达叶子节点时

   {

       printf("找到一个方案");

       for(i=0;i<N;i++)

       {

          printf("%d",a[i]);

       }

       if(now_w>bag)//判断方案是否超重

       {

          printf("\n该方案总价%d,总重%d,超重!不可行!!!\n",now_v,now_w);

       }

       else//如果不超重

       {

          if(now_v>max_value)//判断该方案所获得的价值是不是更优

          {

              max_value=now_v;//更新最优解

          }

          printf("\n该方案总价%d,总重%d,可行\n",now_v,now_w);

       }

       count++;

    }

    else

    {

        for(i=0;i<=1;i++)

        {

            a[t]=i;//记录当前物品选或不选

          now_v=now_v+v[t]*i;//根据0-1值累加价值

          now_w=now_w+w[t]*i;//根据0-1值累加重量

          if(now_w<=bag&&now_v+r[t+1]>max_value) // (限件减枝 约束减枝)

              backpack(t+1,now_v,now_w);//递归到下一层

        }

    }

   return max_value;//返回最大价值

}

1-2回溯法运行结果

动态规划:

int jy[100][100]={0};//记忆数组

int backpack(int i,int m)//i为第i个物品,m为有m元钱

{

   if(i == 0) return 0;//边界

   if(jy[i][m]>0)return jy[i][m];

    if(w[i]>m)

       return jy[i][m]=backpack(i-1,m);//当这个物品装不下时 就不需要比较了

    else

       jy[i][m]=max(backpack(i-1,m),backpack(i-1, m - w[i])+v[i]);

   return jy[i][m];

}

1-1动态规划运行结果图

分析算法及运行时间可知枚举法和回溯法的算法复杂度为O(2^n),而动态规划方法的算法复杂度为O(n)

6.总结

枚举法和回溯的思路较简单但是算法复杂度较高,动态规划的方法需要考虑的问题较多但是大大减低了算法复杂度

动态规划算法具有最优子结构性质,因此动态规划能得到最优解。01背包问题存在重叠子问题,利用备忘录方法避免重复计算相同子问题。

注:贪心算法中,每步贪心决策都无法改变,而忽略了背包的容量,考虑的背包问题的局部最优,而不是全局最优。

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
问题描述: 假设有一个能装入总体积为T的背包和n件体积分别为w1 , w2 , … , wn 的物品,能否从n件物品中挑选若干件恰好装满背包,即使w1 +w2 + … + wn=T,要求找出所有满足上述条件的解。例如:当T=10,各件物品的体积{1,8,4,3,5,2}时,可找到下列4组解: (1,4,3,2) (1,4,5) (8,2) (3,5,2)。 问题提示: 可利用回溯法的设计思想来解决背包问题。首先将物品排成一列,然后顺序选取物品装入背包,假设已选取了前i 件物品之后背包还没有装满,则继续选取第i+1件物品,若该件物品"太大"不能装入,则弃之而继续选取下一件,直至背包装满为止。但如果在剩余的物品中找不到合适的物品以填满背包,则说明"刚刚"装入背包的那件物品"不合适",应将它取出"弃之一边",继续再从"它之后"的物品中选取,如此重复,直至求得满足条件的解,或者无解。 题目之二: 问题描述: 假设有n件物品,这些物品的重量分别是W1 , W2 , … , Wn,物品的价值分别是V1,V2, …,Vn。求从这n件物品中选取一部分物品的方案,使得所选中的物品的总重量不超过限定的重量W(W<∑Wi, i=1,2,┅,n),但所选中的物品价值之和为最大。 问题提示: 利用递归寻找物品的选择方案。假设前面已有了多种选择的方案,并保留了其中总价值最大的方案于数组option[]中,该方案的总价值保存于变量max_value中。当前正在考察新方案,其物品选择情况保存于数组eop[]中。假设当前方案已考虑了i-1件物品,现在要考虑第i件物品:当前方案已包含的物品的重量之和为tw;因此,若其余物品都选择是可能的话,本方案所能达到的总价值的期望值设为tv。引入tv是当一旦当前方案的总价值的期望值也小于前面方案的总价值max_value时,继续考察当前方案已无意义,应终止当前方案而去考察下一个方案。 第i件物品的选择有两种可能: ① 物品i被选择。这种可能性仅当包含它不会超过方案总重量的限制才是可行的。选中之后继续递归去考虑其余物品的选择; ② 物品i不被选择。这种可能性仅当不包含物品i也有可能找到价值更大的方案的情况。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值