01背包问题的三种解法

题目描述:

第一种:递归

每种物品我们都有两种状态取或者不取,出来就是一个树状图

 假设有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]);
	}

}

 

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值