记录结果再利用的 “功态规划”

本文详细解析了01背包问题的解决方法,包括记忆化搜索和动态规划两种核心算法。通过具体的实例,展示了如何利用这两种算法高效求解背包问题。

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

一、记忆化搜索与动态规划

#01 背包问题

在这里插入图片描述

n = 4
(w, v) = { (2, 3), (1, 2), (3, 4) , (2, 2) }
W = 5

7(选择第0 、1 、3 号物品)

【解析】
第一步:先写限制条件,本题有两个(遍历到底,重量不能超过 W )。
遍历到底,回溯;
超重,跳过这个物品;
第二步:分析主结构:
每个物品都有被挑选和不被挑选的情况,并且返回物品的总价值 -> f(i+1,j), f(i+1,j-w[i]) + v[i]
求最大值 -> Math.max(f(i+1,j), f(i+1,j-w[i]) + v[i])

static int n,W;
static int[] w=new int[100],v=new int[100];
public static void main(String[] args) {
	Scanner scan=new Scanner(System.in);
	n=scan.nextInt();
	for(int i=0;i<n;i++) {
		w[i]=scan.nextInt();
		v[i]=scan.nextInt();
	}
	W=scan.nextInt();
	//System.out.println(f1(0,0));
	//System.out.println(f2(0,W));
	solve1();
	solve2();

}

//思路一
///第i个物品,当前重量为j+w[i]
static int f1(int i,int j) {
	if(i==n) return 0;
	//超重
	else if(j+w[i]>W) return f1(i+1,j);
	//主体
	else return Math.max(f1(i+1,j), f1(i+1,j+w[i])+v[i]);
}

//思路二
//第i个物品,剩余可用重量为j
static int f2(int i,int j) {
	//选到最后一个了
	if(i==n) return 0;
	//不能选择(超重)
	else if(j<w[i]) return f2(i+1,j);
	//主功能
	else return Math.max(f2(i+1,j), f2(i+1,j-w[i])+v[i]);
}

1.记忆化搜索

只不过,这种方法的搜索深度是 n ,而且每一层的搜索都需要两次分支,最坏就需要 O (2n)的时间,当 n 比较大时就没办法解了。
在这里插入图片描述
如图所示,f 以(3,2)为参数调用了两次。如果参数相同,返回的结果也应该相同,于是第二次调用时已经知道了结果却向向浪费了计算时间。
让我们在这里把第一次计算时的结果记录下来,省略掉第二次以后的重复计算试试看。

//记忆化搜索一
static int f(int i, int j) {
	//如果已经计算过则使用以前的数据
	if(dp[i][j]>0) return dp[i][j];
	int res;
	
	if (i == n) res=0;
	else if (j + w[i] > W) res=f(i + 1, j);
	else res=Math.max(f(i + 1, j), f(i + 1, j + w[i]) + v[i]);
	
	return dp[i][j]=res;
}
//记忆化搜索二参考思路二自己实现

这微小的改进能降低多少复杂度呢?对于同样的参数,只会在第一次被调用到时执行递归部分,第二次之后都会直接返回。参数的组合不过 nW 种,而函数内只调用2次递归, 所以只需要 O (nW) 的复杂度就能解决这个问题。只需略微改良,可解的问题的规模就可以大幅提高。这种方法一般被称为 记忆化搜索

2.动态规划

接下来,我们来仔细研究一下前面的算法利用到的这个记忆化数组。记dp[i][j]为根据 f 的定义,
从第 i 个物品开始挑选总重小子 j 时,总价值的最大值。于是我们有如下递推式在这里插入图片描述
如上所示,不用写递归函数,直接利用递推式将各项的值计算出来,简单地用二重循环也可以解决这一问题。
在这里插入图片描述

//动态规划一
static void solve2(){
	for(int i=n-1;i>=0;i--){
		for(int j=0;j<=W;j++){
			if(j+w[i]>W)
				dp[i][j]=dp[i+1][j];
			else
				dp[i][j]=Math.max(dp[i+1][j], dp[i+1][j+w[i]]+v[i]);
		}
	}
	System.out.println(dp[0][0]);
}
//动态规划二自己实现

这个算法的复杂度与前面相同,也是 O(nW) ,但是简洁了很多。
以这种方式一步步按顺序求出问题的解的方法被称作动态规划法,也就是常说的 DP 。解决问题时既可以按照如上方法从记亿化搜索出发推导出递推式,熟练、后也可以直接得出递推式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值