01背包 动态规划(三)

本文详细解析了01背包问题的解决方法,从暴力递归到动态规划的转变过程,并给出了具体的实现代码及示例。通过构建动态规划表格,逐步填充并解释每个单元格的意义,帮助读者理解动态规划的核心思想。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

01背包问题详解,暴力递归改动态规划

测试数据:

		int n=5;//物品个数
		int m=20;//背包容量
		int[] weight=new int[]{0,2,3,4,5,9};//物品重量
		int[] value=new int[]{0,3,4,5,8,10};//物品价值

1.递归版本:

private static int knapsack(int n,int m,int[] w,int[] v) {
		if(n==0||m==0){
			return 0;
		}else if((m>w[n])&&((knapsack(n-1, m-w[n], w, v)+v[n])>knapsack(n-1, m, w, v))){
			return knapsack(n-1, m-w[n], w, v)+v[n];
		}else{
			return knapsack(n-1, m, w, v);
		}
	}

2.分析可变参数,哪几个可变参数的值能代表返回状态,几个可变参数,就构造几维表。

    本题中,背包所装得物品的最大价值只与背包容量和物品个数有关,所以dp表为二维:

 

3.根据base case填表:

if(n==0||m==0){
			return 0;
		}

 

 

 

n\m01234567891011121314151617181920
0000000000000000000000
10                    
20                    
30                    
40                    
50                    

4.分析一个普遍位置的规律:

if((m>w[n])&&((knapsack(n-1, m-w[n], w, v)+v[n])>knapsack(n-1, m, w, v))){
			return knapsack(n-1, m-w[n], w, v)+v[n];
		}else{
			return knapsack(n-1, m, w, v);
		}

如果一个位置的列(即背包容量)>它的w[n](即物品质量),要知道这个位置的值,就得知道它(上一行,本列+w[n])+v[n] 元素的值和(上一行,本列) 元素的值,取其二者中最大值;

如果一个位置的列(即背包容量)<= 它的w[n](即物品质量),要知道这个位置的值,就得知道它(上一行,本列)元素的值。

 

补全dp表(略,见下图):

 

n\m01234567891011121314151617181920
00000000000000000000000
10                    
20                    
30                    
40                    
50                    

 

动态规划的代码为:

 

// dp
	private static int dpknapsack(int n, int m, int[] w, int[] v) {
		int[][] dp = new int[n + 1][m + 1];
		// for (int i = 0; i < n + 1; i++) {
		// dp[i][0] = 0;
		// }
		// for (int j = 0; j < m + 1; j++) {
		// dp[0][j] = 0;
		// }
		for (int i = 1; i < n + 1; i++) {
			for (int j = 1; j < m + 1; j++) {
				if (j > w[i]) {
					int value1 = dp[i - 1][j - w[i]] + v[i];
					int value2 = dp[i - 1][j];
					dp[i][j] = value1 > value2 ? value1 : value2;
				} else {
					dp[i][j] = dp[i - 1][j];
				}
			}
		}

		for (int x = 0; x < n + 1; x++) {
			for (int y = 0; y < m + 1; y++) {
				System.out.print(dp[x][y] + "\t");
			}
			System.out.println("");
		}
		return dp[n][m];
	}

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值