01背包问题三种求解方式
** 有n个重量和价值分别为wi,vi的物品,从这些物品中挑选出总重量不超过W的物品,求所有挑选方案中价值总和的最大值。
1≤n≤100
1≤wi,vi≤100
1≤W≤10000
输入:
n=4
(w,v)={(2,3),(1,2),(3,4),(2,2)}
W=5
输出:
7(选择第0,1,3号物品)
因为对每个物品只有选和不选两种情况,所以这个问题称为01背包。*
package LanqiaoBeautiful._8Dp;
import java.util.Arrays;
public class packsack_01 {
static int[] w = {2,1,3,2};//重量表
static int[] v = {3,2,4,2};//价值表
static int n=4;//物品数量
static int W=5;//背包承重极限
public static void main(String[] args) {
int ww=W;
int ans = dfs(0,ww);
System.out.println(ans);
//记忆型递归
rec=new int[n][W+1];
for(int i=0;i<n;i++) {
Arrays.fill(rec[i], -1);//数组赋初值-1
}
ww=W;
ans = m(0,ww);
System.out.println(ans);
//dp
System.out.println(dp());
}
/*
* 时间复杂度是2^n
*/
static int dfs(int i, int ww) {
if(ww<0) return 0;//装不进去
if(i==n) return 0;//没东西可选了
int v2 = dfs(i+1,ww);//不选择当前物品
if(ww>=w[i]) {
int v1 = v[i]+dfs(i+1,ww-w[i]);//选择当前物品
return Math.max(v1,v2);
}else {
return v2;
}
}
static int[][] rec;
/*
* 记忆型递归
*/
static int m(int i,int ww) {
if(ww<=0) return 0;//装不进去
if(i==n) return 0;//没东西可选了
//1.计算之前先查询
if(rec[i][ww]>=0)
return rec[i][ww];
int v2 = m(i+1,ww);//不选择当前物品
int ans;
if(ww>=w[i]) {
int v1 = v[i]+m(i+1,ww-w[i]);//选择当前物品
ans=Math.max(v1, v2);
}else {
ans=v2;
}
//2.计算之后做保存
rec[i][ww]=ans;
return ans;
}
//dp解法
static int dp() {
int[][] dp = new int[n][W+1];
//初始化dp表的第一行
for(int i=0;i<W+1;i++) {
if(i>=w[0]) {// 每种容量-0号物品
dp[0][i]=v[0];
}else {
dp[0][i]=0;
}
}
//其他行
for(int i=1;i<n;i++) {
// j是列,也是背包的剩余容量
for(int j=0;j<W+1;j++) {
if(j>=w[i]) {//要的起
int i1 = v[i]+dp[i-1][j-w[i]];//选择当前物品即i号物品,剩余容量
int i2 = dp[i-1][j];
dp[i][j]=Math.max(i1, i2);
}else {
dp[i][j]=dp[i-1][j];
}
}
}
return dp[n-1][W];
}
}
对于第一种直接求解的话会有大量重复的计算,时间复杂度偏高,记忆型递归是在直接递归的基础上进行了优化,再次优化就是更高效率的dp了。