【软考总结】-<算法>动态规划法--0-1背包问题

简介: 在上篇博客中,我们讲了动态规划法在最长公共子序列问题中的应用,(详情请见博客《算法:动态规划法--最长公共子序列》)。这次学习了0-1背包问题,对动态规划法的思想理解了更深了一层,以下是我的简单理解,希望能为路过的读者带来帮助。

在上篇博客中,我们讲了动态规划法在最长公共子序列问题中的应用,(详情请见博客《算法:动态规划法--最长公共子序列》)。这次学习了0-1背包问题,对动态规划法的思想理解了更深了一层,以下是我的简单理解,希望能为路过的读者带来帮助。


第一,动态规划法思想

   1、简单了解分治法和贪心法


分治,分治,分而治之。分治算法的基本思想是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同。求出子问题的解,就可得到原问题的解。贪心法,基本思想是整体最优解可以通过一系列局部最优得到,所以只需得到局部最优解,每一步都只考虑一个数据,所以不一定是整体最优。  


2、三法相比,理解动态规划法


贪心法的特征是由顶向下,一步一步地做出贪心选择,但不足的是,如果当前选择可能要依赖子问题的解时,则难以通过局部的贪心策略达到全局最优解。相比而言,动态规划则可以处理不具有贪心实质的问题。


   而用分治法解决问题时,由于子问题的数目往往是问题规模的指数函数,因此对时间的消耗太大。动态规划的思想在于,如果各个子问题不是独立的,不同的子问题的个数只是多项式量级。如果我们能够保存已经解决的子问题的答案,而在需要的时候再找出已求得的答案,这样就可以避免大量的重复计算。由此而来的基本思路是,用一个表记录所有已解决的子问题的答案,不管该问题以后是否被用到,只要它被计算过,就将其结果填入表中。这就是动态规划法的基本思想


第二,动态规划法求解0-1背包问题




20170514104723875.png




***************************************问题描述********************************************


  有n个物品,第i个物品价值为vi,重量为wi,其中vi和wi均为非负数,背包的容量为W,W为非负数。现需要考虑如何选择装入背包的物品,使装入背包的物品总价值最大。该问题以形式化描述如下:


20170514102925865.jpg

目标函数为 :


20170514102930598.jpg

约束条件为:

  满足约束条件的任一集合(x1,x2,...,xn)是问题的一个可行解,问题的目标是要求问题的一个最优解。考虑一个实例,假设n=5,W=17, 每个物品的价值和重量如表9-1所示。可将物品1,2和5装入背包,背包未满,获得价值22,此时问题解为(1,1,0,0,1)。也可以将物品4和5装入背包,背包装满,获得价值24,此时解为(0,0,0,1,1)。


*********************************动态规划法求解过程*****************************************    

20170514103014145.jpg

1、刻画最优解结构


背包求解过程可看做进行一系列决策的过程,即决定哪些物品应该放入背包,哪些不放入。不能物品i装入多次,也不能只装入物品的一部分。如果一个问题的最优解包含了物品n,Xn=1,那么,其他X1,X2…Xn-1一定构成子问题1,2,3…n-1在容量为W-wn时的最优解。如果不包含物品n,Xn=0,那么,其他X1,X2…Xn-1一定构成子问题1,2,3…n-1在容量为W时的最优解,即在此容量下,不放这个物品。


2、递归定义最优解的值


c[I,w]表示背包容量为wi个物品得到的最优解的总价值。显然,我们是要求解c[n,w]。(这里注意,不是第i个物品,是背包里存在i个物品)


20170514103214943.jpg



3、计算背包问题最优解的值。

 (为了让软考的小朋友更好的理解,此代码复制自《软件设计师教程》第4版复制)

C语言代码:


int** KnapsackDP(int n,int W,int* Weights,float* Values) { 
int i, w ; 
/ * 为 二 维 数 组 申 请 空 间 * / 
int** c = (int **)malloc(sizeof(int * ) *(n + l)); 
for (i = 0 ; i < = n; i++) 
c[i]= (int *)malloc(sizeof(int)*(W + l)); 
/ * 初 始 化 二 维 数 组 * / 
For(w=0;w <W;w++) 
   c[0][w] = 0; //i=0的一行值全为0;
for(i=1;i<= n;i++) {                    //i在外循环,在i一定时,随着背包容量增加,是否放该物品
   c[i][0] = 0;                        //w=0的一整列全为0;
  for(w = 1 ;w < = W;w++) { 
  if(Weights[i-1] < = w) { / * 如 果 背 包 剩 余 重 量 大 于 物 品 重 量 
    if(Values[i-1]+c[i-1][w-Weights[i-1]]>c[i-1][w])
    { /* 重 量 为 w 的 背 包 中有 该 物 品 * / 
      c[i][w] = Values[i-1] + c[i-1][w -Weights[i-1]];
    }
    else{ 
    /*重 量 为 w 的 背 包 中没有 该 物 品 * / 
      c[i][w]  = c[i-1][w]; 
    }
  }
  Else
    c[i][w]  =c[i-1][w];
}
}
Return c ;
}


时间复杂度:O(nW)
得到记录表格:


image.jpeg

4、根据计算结果构造问题最优解

Void OutPutKnapsackDP(int n,int w,int *Weights,float *values,int**c) { 
Int x[n] ; 
int 1 ; 
For (i=n;j>1;i--) { 
   if(c[i][w]==c[i-1][w]) / * 重 量 为 w 的 最 优 选 择 的 背 包 中 不 包 含 该 物 品 */ 
      x[i-1] = 0 ; 
   Else{
      x[i-1] = 1 ;
      W =W-Weightst[i-1]; / * 更 新 背 包 目 前 的 最 大 容 量 * / 
   }
}
if(c[1][W]=0) / * 第 一 个 物 品 不 在 背 包 * / 
      x[0] =0; 
else 
/ *第 一 个 物 品在背 包中* / 
       x[0] =1;
For(i=0;i<n;i++)
      if(x[i]==1)
            printf("Weight:%d,Value:%f\n",Weights[i],Values[i]);
}


时间复杂度是:O(n)


注:


在C语言中


%d,用来输出十进制整数


%f,用来输出实数(包括单,双精度),以小数形式输出



****************************************举例说明********************************************


   当背包容量为8(w=8),可以放2个物品时(i=2),背包的最大价值是多少?


1、判断背包的容量是否可以容下此物品:


    Weights[i-1] =Weights[1]=4,(因为数组的下标从0开始,所以这里指第二个物品的重量是4),4<8,第二个物品可以放入背包。


2、根据价值,判断是否将此物品放入背包


   假设此物品已经放入背包,那么根据刻画的最优结构“如果一个问题的最优解包含了物品n,Xn=1,那么,其他X1,X2…Xn-1一定构成子问题1,2,3…n-1在容量为W-wn时的最优解。”计算价值


  Values[i-1]+c[i-1][w-Weights[i-1]]=Values[1]+c[1][4]=9


  即,第二个物品的价值5+背包容量位(8-4)时,放两个物品时的价值(此情况在之前已经计算出,c[1][4]=4)


第三,总结


在什么情况下可以使用动态规划法?1、有最优子结构:一个问题有很多解,每个解对应一个值,我们希望找到最优解;2、重叠子问题:每个子问题之间不是相互独立的,求解第二个问题,可能用到第一个问题的解。


结合最长公共子序列问题和0-1背包问题,适合动态规划法求解的问题,经分解得到的子问题保存已解决的子问题的答案,在需要时再找出已求得的答案,这样可以避免大量的重复计算,从而得到多项式时间的算法。


相关文章
|
4月前
|
机器学习/深度学习 存储 算法
动态规划算法深度解析:0-1背包问题
0-1背包问题是经典的组合优化问题,目标是在给定物品重量和价值及背包容量限制下,选取物品使得总价值最大化且每个物品仅能被选一次。该问题通常采用动态规划方法解决,通过构建二维状态表dp[i][j]记录前i个物品在容量j时的最大价值,利用状态转移方程避免重复计算子问题,从而高效求解最优解。
583 1
|
4月前
|
算法 搜索推荐 Java
贪心算法:部分背包问题深度解析
该Java代码基于贪心算法求解分数背包问题,通过按单位价值降序排序,优先装入高价值物品,并支持部分装入。核心包括冒泡排序优化、分阶段装入策略及精度控制,体现贪心选择性质,适用于可分割资源的最优化场景。
357 1
贪心算法:部分背包问题深度解析
|
4月前
|
存储 算法 搜索推荐
软考算法破壁战:从二分查找到堆排序,九大排序核心速通指南
专攻软考高频算法,深度解析二分查找、堆排序、快速排序核心技巧,对比九大排序算法,配套动画与真题,7天掌握45%分值模块。
228 1
软考算法破壁战:从二分查找到堆排序,九大排序核心速通指南
|
12月前
|
算法 Java C++
【潜意识Java】蓝桥杯算法有关的动态规划求解背包问题
本文介绍了经典的0/1背包问题及其动态规划解法。
424 5
|
算法
动态规划算法学习三:0-1背包问题
这篇文章是关于0-1背包问题的动态规划算法详解,包括问题描述、解决步骤、最优子结构性质、状态表示和递推方程、算法设计与分析、计算最优值、算法实现以及对算法缺点的思考。
690 2
动态规划算法学习三:0-1背包问题
|
存储 算法
算法之背包问题
本文讨论了可分背包问题和0-1背包问题的区别及解决方法,其中可分背包问题可以使用贪心算法解决,而0-1背包问题则通常采用动态规划方法来找到最大价值的解决方案。
221 0
算法之背包问题
|
算法 C++
【算法】DP背包问题(C/C++)
【算法】DP背包问题(C/C++)
|
算法 Java 测试技术
算法设计(动态规划实验报告) 基于动态规划的背包问题、Warshall算法和Floyd算法
这篇文章介绍了基于动态规划法的三种算法:解决背包问题的递归和自底向上实现、Warshall算法和Floyd算法,并提供了它们的伪代码、Java源代码实现以及时间效率分析。
算法设计(动态规划实验报告) 基于动态规划的背包问题、Warshall算法和Floyd算法
|
存储 算法 C语言
软考中级之数据库系统工程师笔记总结(二)数据结构与算法
软考中级之数据库系统工程师笔记总结(二)数据结构与算法
185 0
|
算法 Java 决策智能
Java数据结构与算法:动态规划之背包问题
Java数据结构与算法:动态规划之背包问题

热门文章

最新文章