题目描述:
第一种:递归
每种物品我们都有两种状态取或者不取,出来就是一个树状图
假设有4个物品,背包容量为5
import java.util.Scanner;
//01型背包问题
public class case01背包问题 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int[] w = new int[n];
int[] v = new int[n];
for(int i = 0;i<n;i++) {
w[i] = sc.nextInt();
v[i] =sc.nextInt();
}
int price = dfs(w,v,0,n,m);
System.out.println(price);
}
public static int dfs(int[] w,int[] v,int index,int n,int m) {
//背包装不下了
if(m<=0) {
return 0;
}
//没有物品了
if(index==n) {
return 0;
}
//不装该物品
int v1 = dfs(w,v,index+1,n,m);
if(m>=w[index]) {
int v2 = dfs(w,v,index+1,n,m-w[index])+v[index];//装入物品
return max(v1,v2);
}
else {
return v1;
}
}
public static int max(int v1,int v2) {
if(v1>=v2) {
return v1;
}
else {
return v2;
}
}
}
第二种:记忆型递归
通过上面我们可以发现有些地方会重复计算,所以为了避免重复计算所以用记忆型递归
import java.util.Arrays;
import java.util.Scanner;
//01型背包问题
public class 记忆型递归解决01背包问题 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int[] w = new int[n];
int[] v = new int[n];
for(int i = 0;i<n;i++) {
w[i] = sc.nextInt();
v[i] =sc.nextInt();
}
int[][] temp = new int[n][m+1];
for(int i = 0;i<n;i++) {
Arrays.fill(temp[i],-1);
}
int price = dfs2(w,v,0,n,m,temp);
System.out.println(price);
}
//记忆型递归解决:因为递归有时候数据是一样的就不用重复计算了
public static int dfs2(int[] w,int[] v,int index,int n,int m,int[][] temp) {
int res;
//背包装不下了
if(m<=0) {
return 0;
}
//没有物品了
if(index==n) {
return 0;
}
//计算之前先查询
if(temp[index][m]>=0) {
return temp[index][m];
}
//不装该物品
int v1 = dfs2(w,v,index+1,n,m,temp);
if(m>=w[index]) {
int v2 = dfs2(w,v,index+1,n,m-w[index],temp)+v[index];//装入物品
res = max(v1,v2);
}
else {
res = v1;
}
temp[index][m] = res;//记录
return res;
}
public static int max(int v1,int v2) {
if(v1>=v2) {
return v1;
}
else {
return v2;
}
}
}
第三种:dp
import java.util.Scanner;
//代码没有优化
public class dp解决01背包问题 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();//物品的数量
int m = sc.nextInt();//最大的装载重量
int[] w = new int[n];
int[] v = new int[n];
for(int i = 0;i<n;i++) {
w[i] = sc.nextInt();
v[i] =sc.nextInt();
}
int res = dp(w,v,n,m);
System.out.println(res);
}
public static int dp(int[] w,int[] v,int n,int m) {
int[][] dp = new int[n][m+1];
//初始化第一行数据
for(int i =0;i<=m;i++) {
if(i>=w[0]) {
dp[0][i] = v[0];
}else {
dp[0][i] = 0;
}
}
//算出其他行的数据
for(int row = 1;row<n;row++) {
for(int col = 0;col<=m;col++) {
if(col>=w[row]) {//背包的容量大于这个物品的重量
dp[row][col] = Math.max(v[row]+dp[row-1][col-w[row]], dp[row-1][col]);
}else {
dp[row][col] = dp[row-1][col];
}
}
}
return dp[n-1][m];
}
}
import java.util.Scanner;
public class dp解决01背包代码优化过 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();//物品的数量
int m = sc.nextInt();//最大的装载重量
int[][] dp = new int[n+1][m+1];
for(int i = 1;i<=n;i++) {
int w = sc.nextInt();
int v =sc.nextInt();
for(int j = 1;j<=m;j++) {
if(j>=w) {
dp[i][j]=Math.max(dp[i-1][j], dp[i-1][j-w]+v);
}else {
dp[i][j]=dp[i-1][j];
}
}
}
System.out.println(dp[n][m]);
}
}