感谢陈小玉老师的讲解,原视频链接https://www.bilibili.com/video/BV1jT4y1o71J/?spm_id_from=pageDriver&vd_source=375b43daeb4ff3d4c343eabe5ef570b9
哪些问题可以使用dp(动态规划)?
- 最优子结构(原问题最优解包含子问题最优解)
- 子问题重叠
- 无后效性
上图中F3 F2 F1都进行性了重复求解就导致了子问题重叠
常见的dp模板
求解动态规划问题步骤
实例填表过程
物品 | 重量 | 价格 |
---|---|---|
吉他(G) | 1 | 1500 |
音箱(S) | 4 | 3000 |
电脑(L) | 5 | 2000 |
物品 | 0磅 | 1磅 | 2磅 | 3磅 | 4磅 |
---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | |
吉他(G) | 0 | 1500(G) | 1500(G) | 1500(G) | 1500(G) |
音箱(S) | 0 | 1500(G) | 1500(G) | 1500(G) | 3000(S) |
电脑(L) | 0 | 1500(G) | 1500(G) | 2000(L) | 2000(L)+1500(G) |
- v[i][0]=v[0][i] = 0; 表示填入的表第一行和第一列是0
- 当w[i]>j时;v[i][j]=v[i-1][j]当新增的商品的容量大于当前背包的容量时,就直接使用上一个单元格的装入策略
- 当j>=w[i]时:v[i][j]=max{v[i-1][j],v[i-1][j-w[i]]+v[i]} 当准备加入的新增商品的容量小于当前背包容量,装入的方式 v[i-1]j:就是上一个单元格转入的最大值 v[i-1][j-w[i]]:装入i-1个商品到剩余空间 j-w[i] 的最大值
public class KnapsackProblem {
public static void main(String[] args) {
int[] w = {1,4,3};//物品重量
int[] val = {1500,3000,2000};//物品价值
int m = 4; //背包的容量
int n = val.length; //物品个数
int[][] path = new int[n+1][m+1];//记录商品让如情况
//v[i][j]表示在前i个物品中能够装入容量为j的背包的最大价值
int[][] v = new int[n+1][m+1];
//初始化第一行,第一列,默认是0
//设置第一列为 0
for (int i = 0; i < v.length; i++) {
v[i][0]=0;
}
//设置第一行为 0
for (int j = 0; j < v[0].length; j++) {
v[0][j] = 0;
}
//根据公式来动态规划处理
for (int i = 1; i < v.length; i++) { //不处理第一行
for (int j = 1 ; j < v[0].length; j++) { //不处理第一列
//因为i从1开始
if(w[i-1]>j){
v[i][j] = v[i-1][j];
}else{
//因为i从1开始
v[i][j] = Math.max(v[i-1][j],val[i-1]+v[i-1][j-w[i-1]]);
}
}
}
for (int i = 0; i < v.length; i++) {
for (int j = 0; j < v[0].length; j++) {
System.out.print(v[i][j]+" ");
}
System.out.println();
}
}
}