动态规划0-1背包

来源:互联网 发布:c语言解惑 pdf下载 编辑:程序博客网 时间:2024/05/29 17:16

1.

(1)动态规划将问题划分成子问题,在合并的结果。子问题是彼此独立的。

(2)动态规划将已计算过的子问题结果保存到表中,是一种以空间换时间的方式。

(3)动态规划的初始化条件注意,不要写错。找出递归函数关系式

(4)与记忆搜索相比,动态规划的计算具有一定的顺序性,比如b的结果依赖a的结果,要先a在b,而记忆搜索哪个先来就先计算哪个,将其结果保存即可。



2、常见的动态规划问题:

零一背包问题

最长公共子序列LCS问题

最长升序子序列LIS问题

零钱问题

台阶问题

Floyd算法



3.0-1背包:

题目:一个背包有一定的承重cap,有N件物品,每件都有自己的价值,记录在数组v中,也都有自己的重量,记录在数组w中,每件物品只能选择要装入背包还是不装入背包,要求在不超过背包承重的前提下,选出物品的总价值最大。给定物品的重量w价值v及物品数n和承重cap。请返回最大总价值。

[1,2,3],[1,2,3],3,6返回:6

思路:

N件物品,每一件有自己的重量和自己的价值,分别用一个数组给出,背包有一个限制总重量为cap,要求在满足重量不超过cap的前提下,向背包中装入物品,使得总的价值最大,求出最大价值


dp[i][j],即使用前i个物品,在重量不超过j时的最大价值为dp[i][j],注意对于重量,由于只给定了最大的范围cap,但是在分解问题时应该将其从0开始枚举,即枚举重量从0开始直到cap,总共有cap+1个值,同理对于找零钱问题,只给定了一个最大值aim,但是在分解为题时应该从0开始直到aim考虑aim+1个值。

初始条件:

第一行的值,表示使用第一将物品w[0]来装包,显然当容量小于w[0]时无法装入因此价值为0,之后可以装入,于是最大价值显然就是v[0]=4;

第一列的值,表示使用前i个物品来装包,当容量为0时的最大价值,显然一个都放不下,所以价值都为0。

对于任意的dp[i][j]2种情况:第i件物品放还是不放:

(1)如果i物品不装入,dp[i-1][j];

(2)如果i物品装入,物品i的重量为w[i],物品i的价值为v[i],那么即是求在重量限制j-w[i]条件下的最大价值,即转变为求dp[i-1][j-w[i]],求的dp[i-1][j-w[i]]后,此时的价值为dp[i-1][j-w[i]]+v[i]

dp[i][j]=Math.max(dp[i-1][j];dp[i-1][j-w[i]]+v[i]);需要注意的是,在求dp[i-1][j-w[i]]时,对于有些j并不一定大于w[i],即j-w[i],此时表示无法装入物品i,于是此时dp[i][j]应该直接等于dp[i-1][j];于是在求dp[i][j]时对j-w[i]进行一个if判断然后使用Math.max判断或者直接取dp[i-1][j]即可。

动态规划4部曲:

①创建动态规划二维数组存储答案dp[n][cap+1];

②计算第1行和第1列的元素值

第1行:从j=w[0]开始dp[0][j]=v[0];

第1列:dp[i][0]=0;

③从上到下,从左到右计算任意dp[i][j],根据[j-w[i]<0使用不同的计算逻辑

④返回结果,右下角的值dp[n-1][aim]就是所求的结果;

[java] view plain copy
 print?
  1. import java.util.*;  
  2. //01背包问题:动态规划4部曲  
  3. public class Backpack {  
  4.     public int maxValue(int[] w, int[] v, int n, int cap) {  
  5.         //特殊输入  
  6.         if(w==null||v==null||n<=0||cap<=0return 0;  
  7.         //①创建动态规划数组存放答案dp[][]  
  8.         int[][] dp=new int[n][cap+1];  
  9.         //②计算dp[][]第1行值  
  10.         for(int i=w[0];i<=cap;i++){  
  11.             dp[0][i]=v[0];  
  12.         }  
  13.         //②计算dp[][]第1列的值:全是0,默认也是0,故无需操作  
  14.         //③从上到下,从左到右计算任意dp[i][j]  
  15.         for(int i=1;i<n;i++){  
  16.             for(int j=1;j<=cap;j++){  
  17.                 if(j-w[i]>=0){  
  18.                     dp[i][j]=Math.max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);  
  19.                 }else{  
  20.                     dp[i][j]=dp[i-1][j];  
  21.                 }  
  22.             }  
  23.         }  
  24.         //④返回dp[][]右下角即为所求结果  
  25.         return dp[n-1][cap];  
  26.     }  
  27. }  

代码二:只使用1个数组,


public class Backpack {    public int maxValue(int[] w, int[] v, int n, int cap) {        // dp[x][y]表示物品数量为x,重量不超过y时背包中的总价值        //两种情况:1.将x物品不加入到背包中,那么前x-1件物品的总重量不应该超过y。dp[x][y] = dp[x-1][y]                //2.将x物品加入到背包中,那么前x-1前物品的总重量不应该超过y-w(x),因此dp[x][y] = dp[x-1][y-w(x)]+v(x);        int[] dp = new int[cap+1];                  for(int i=0;i<n;i++){//控制物品的数量            for(int j=cap;j>=w[i];j--){//空背包中不能超重                dp[j] = dp[j]>=dp[j-w[i]]+v[i]?dp[j]:dp[j-w[i]]+v[i];//选取j加入书包与j不加入书包的较大值            }        }                  return dp[cap];//返回数组的最后一位即是最大总价值          }}



[java] view plain copy
 print?
  1. import java.util.*;  
  2. public class Backpack {  
  3.     public int maxValue(int[] w, int[] v, int n, int cap) {  
  4.         // write code here  
  5.         int dp[] = new int[cap + 1];  
  6.         for(int i = 0; i < n; i++ ){  
  7.             for(int j = cap; j >= w[i]; j--){  
  8.                 dp[j] = Math.max(dp[j], dp[j - w[i]] + v[i]);  
  9.             }  
  10.         }  
  11.         return dp[cap];  
  12.     }  
  13. }  


原创粉丝点击