题目:有n个重量和价值分别为wi,vi的物品,从这些物品中挑选出总重量不超过c的物品,求所以挑选方案中价值总和的最大。
1<=n<=100
1<=wi,vi<=100
1<=c<=10000
输入:
n=4
(w,v)={(2,3),(1,2),(3,4),(2,2)}
c=5;
输出:
7
//因为这个问题只有选和不选两种情况,所以叫做01背包问题。
方法一:递推O(n^2)
public class pro01背包 {
static int[] w= {2,1,3,2};//重量表
static int[] v= {3,2,4,2};//价格表
static int n=4;//物品数量
static int c=5;//背包的承重极限
public static void main(String[] args) {
int W=c;
int ans=dfs(0,W);
System.out.println(ans);
}
private static int dfs(int i, int W) {
if(W<=0) return 0;//装不进去了
if(i==n) return 0;//没东西可选了
int v2=dfs(i+1,W);//不选择当物品
if (W>=w[i]) {
int v1=v[i]+dfs(i+1,W-w[i]);//选择当前物品
return Math.max(v1, v2);
}else {
return v2;
}
}
}
方法二:记忆型递归:(重叠问题不重复求解)
第一个表示序号,序号越小表示你选择的范围越大(从i开始往后选)第二个表示,你的背包现在的容量。与递推类似,只是要定义一个变量来存储是否已经出现过,如果已经出现过,则直接查询调用。
import java.util.Arrays;
public class pro01背包记忆递归 {
static int[] w= {2,1,3,2};//重量表
static int[] v= {3,2,4,2};//价格表
static int n=4;//物品数量
static int c=5;//背包的承重极限
static int[][] rec;
public static void main(String[] args) {
int W=c;
rec=new int[n][c+1];
for (int i = 0; i < n; i++) {
Arrays.fill(rec[i], -1);
}
W=c;
int ans=m(0,W);
System.out.println(ans);
}
private static int m(int i, int W) {
if(W<=0) return 0;
if(i==n) return 0;
//1.计算之前先查询
if (rec[i][W]>=0) {
return rec[i][W];
}
int v2=m(i+1,W);//不选择当前物品
int ans;
if (w[i]<=W) {
int v1=v[i]+m(i+1,W-w[i]);
ans=Math.max(v1, v2);
}else {
ans=v2;
}
//2.计算之后做保存
rec[i][W]=ans;
return ans;
}
}