背包问题
博主第一次写博客,不喜勿喷
0-1背包
0-1背包问题新建的dp表可以是一维或二维,二维对于小白来说会比较好理解,而一维的为了节省掉一点空间,就相对应的会提高理解的难度。
m[i],v[i]分别表示重量和价值,N, M分别表示物品数量和重量
首先上二维的代码
static void maxDp() {
for(int i = 0; i < N; i++) {
for(int j = M; j >=m[i]; j--) {
//用到i+1是因为我的m[i]和v[i]是从下标为0开始读入数据的
dp[i+1][j] = Math.max(dp[i][j], dp[i][j-m[i]]+v[i]);
}
}
System.out.println(dp[N][M]);
}
二维dp十分好理解,用i 与 i+1来区分状态。
看过很多博客都说0-1背包第二个for循环就要逆序写,完全背包就顺序写。。。其实换成二维的时候0-1背包第二个for循环顺序写也是没问题的- -|| 这其实是理解两个背包问题不同的最重要的地方了
然后再上一维dp的代码
static void maxDp1() {
for(int i = 0; i < N; i++) {
for(int j = M; j >=m[i]; j--) {
dp1[j] = Math.max(dp1[j], dp1[j-m[i]]+v[i]);
}
}
System.out.println(dp1[M]);
}
完全背包
接着是完全背包的代码
static void maxDp2() {
for(int i = 0; i < N; i++) {
for(int j = m[i]; j <= M; j++) {
dp2[j] = Math.max(dp2[j], dp2[j-m[i]]+v[i]);
}
}
System.out.println(dp2[M]);
}
然后实际代码就只有一行的区别。。实际上为什么0-1背包要逆序呢。。首先要理解 i是表示第i个物品的意思 因为逆序的状态转移的过程不会影响前者,而反过来完全背包恰恰就需要前者影响后者(前者影响后者就表示该物品被多次放入背包,后者不受前者影响就表示物品只能一次放入背包)
多重背包
然后关于多重背包,多重背包就是多了个参数k,k表示物品最多可以放入的数量。。可以用个很笨的方法多引入一个k然后再跑一次循环的状态转移= =这是我一开始想到的。
然鹅,,实际上把每个参数k的物品都看成是一种新的物品就好了。。
例如:k = 3, m[i] = 2, v[i] = 4;
就看成多了两种物品,一种是m[i] = 4, v[i] = 8,另一种是m[i] = 6, v[i] = 12;
然后再看成是0-1背包问题来解就好了。。
然后附上转换方式
int len = N;
for(int i = 0; i < len; i++) {
for(int j = 2; j <= k[i]; j++) {
m[N] = m[i]*j;
v[N] = v[i]*j;
N++;
}
}
剩下的换成0-1背包来做的代码就不加附上了。。
只附上了理解性代码,仅为了引发思考,不喜勿喷