01背包问题中二维数组大小为dp[n][w]仍是dp[n+1][w+1]的问题

关于dp数组大小,边界,循环上线,由于这几个值在代码化的时候是有关联的,一开始会以为有点不清不楚的,可是这个问题自己只要理清楚一次就不会再有问题了。java

两种方式都是能够的,这里建议使用dp[n+1][w+1]的方式创建数组,数组

有如下几个好处:spa

1.动态的数值不用加一减一(dp数组)get

2.循环上限直接采用限制条件n和w就能够了,循环开始更符合现实含义循环

 

众所周知01背包问题由如下部分构成:static

n选择的数量,01背包中为物品的数量,co

w开销限制,01背包中为背包大小,new

g数组,每一个选择的价值,return

p数组,每一个选择的开销。背包问题

dp[n][w]表示在n个选择的状况和w个开销限制的状况下,最优解。

动态转移方程为dp[n][w]=max(dp[n-1][w],dp[n-1][w-p[i]]+g[i]),表示dp[n][w]的最优解,为不选择ni时候的最优解,和选择ni时候的最优解中的较优解组成。i表示有没有第i个选择。

 

dp[n+1][w+1]演示:

public static int[][] getMostGold2(int n, int w ,int[] g,int[] p){
int[][] dp = new int[n+1][w+1];
//        for (int j = 0; j <=w; j++) {
// dp[0][j]=0;
// }

for (int i = 1; i <=n; i++) {
for (int j = 1; j <=w ; j++) {
if(j>=p[i-1])
dp[i][j]=Math.max(dp[i-1][j],dp[i-1][j-p[i-1]]+g[i-1]);
else
dp[i][j]=dp[i-1][j];
}
}
return dp;

固定边界的时候,不须要额外固定,由于java中数组初始为0,循环i和j都从1开始,更符合现实,从一个选择和一个限制开始,为0其实没有实际意义。

由于数组长度是n+1和w+1,因此循环上线直接n和w。循环中涉及到的p[i]和g[i]都要-1,i是实际的i,比数组p和g中的大1。

输出整个结果的时候i和j也都是从1开始,dp[i+1][j+1]是最优解。

 

 

dp[n][w]演示:

public static int[][] getMostGold2(int n, int w ,int[] g,int[] p){
int[][] dp = new int[n][w];
for (int j = 0; j <w; j++) {
if(j+1>=p[0])
dp[0][j]=g[0];
else
dp[0][j]=0;
}
for (int i = 1; i <n; i++) {
for (int j = 0; j < w; j++) {
if (j +1 >= p[i] && (j - p[i])>=0) {
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - p[i]] + g[i]);
}
else
dp[i][j] = dp[i - 1][j];
}
}
return dp;
}

dp[n][w]的实现就会麻烦一些,首先须要计算边界,即为第一行,有一个选择的时候,没有边界不会终止。

并且由于j+1才是实际上j表达的数量现实,因此和p[i]比较的时候要+1,而且还要保持(j - p[i])>=0),否则j+1=p[i]的时候,dp[i-1][-1]的状况,这个是最麻烦的!!

 

其余一些状况dp[n][w+1]和dp[n+1][w]就不演示了,逗比dp[n][w]好,可是没有dp[n+1][w+1]明朗!

n+1和n的区别就在因而否须要首先计算边界,w和w+1实际意义上转换比较绕,建议不要用w,尽可能用w+1,这样第一列为空,后面的列号和实际限制数量数值上是一致的,便于理解!

相关文章
相关标签/搜索