【软考总结】-<算法>动态规划法--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背包问题,适合动态规划法求解的问题,经分解得到的子问题保存已解决的子问题的答案,在需要时再找出已求得的答案,这样可以避免大量的重复计算,从而得到多项式时间的算法。


相关文章
|
8天前
|
机器学习/深度学习 算法 C++
【洛谷 P2240】【深基12.例1】部分背包问题 题解(贪心算法)
**深基12.例1**是部分背包问题,$N$堆金币,每堆$(m_i, v_i)$,$T$承重限制。按金币单价降序装包,保证价值最大化。输入$N,T$及每堆金币详情,输出两位小数的最大价值。示例:输入$4,50$,输出$240.00$。AC代码使用C++,通过排序和迭代实现。
20 0
|
4天前
|
算法 Java 决策智能
Java数据结构与算法:动态规划之背包问题
Java数据结构与算法:动态规划之背包问题
|
1月前
|
算法
算法系列--动态规划--背包问题(2)--01背包拓展题目(下)
算法系列--动态规划--背包问题(2)--01背包拓展题目(下)
26 0
算法系列--动态规划--背包问题(2)--01背包拓展题目(下)
|
1月前
|
算法
算法系列--动态规划--背包问题(5)--二维费用背包问题(下)
算法系列--动态规划--背包问题(5)--二维费用背包问题(下)
19 0
|
1月前
|
算法
算法系列--动态规划--背包问题(5)--二维费用背包问题(上)
算法系列--动态规划--背包问题(5)--二维费用背包问题(上)
25 0
|
1月前
|
算法
算法系列--动态规划--背包问题(4)--完全背包拓展题目(下)
算法系列--动态规划--背包问题(4)--完全背包拓展题目(下)
27 0
|
1月前
|
算法
算法系列--动态规划--背包问题(4)--完全背包拓展题目(上)
算法系列--动态规划--背包问题(4)--完全背包拓展题目(上)
23 0
|
1月前
|
算法
算法系列--动态规划--背包问题(3)--完全背包介绍(下)
算法系列--动态规划--背包问题(3)--完全背包介绍(下)
26 0
|
1月前
|
算法
算法系列--动态规划--背包问题(3)--完全背包介绍(上)
算法系列--动态规划--背包问题(3)--完全背包介绍
26 0
|
1月前
|
算法
算法系列--动态规划--背包问题(2)--01背包拓展题目(上)
算法系列--动态规划--背包问题(2)--01背包拓展题目
26 0