代码随想录第四十四天|完全背包、518. 零钱兑换 II 、 377. 组合总和 Ⅳ

完全背包

视频讲解与代码:代码随想录

小节:完全背包和0-1背包不同的地方是完全背包中的物品可以取无限次,而0-1背包的物品只能取一次,因此完全背包在进行遍历时都是从小到大进行遍历(原因在0-1背包中说过,从前往后,可以多次取物品);如果只是考虑能够装下的最大物品价值,背包于物品的遍历顺序都是可以颠倒的,但是都要注意满足j >= weight[i]这个条件;如果要考虑装满背包的方法次数问题的话,有两种情况,情况一是组合问题,那么此时先遍历物品,再遍历背包,这是背包中的物品都是按着下标从大到小进行排列的,如{1, 5},情况二是排序问题,先遍历背包,再遍历物品,此时背包中的物品会有成组的下标,如{1, 5}和{5, 1},这是两种不同的方法(这一种我现在还没搞懂)。

518. 零钱兑换 II

1代码展示

//518.零钱兑换
int change(int amount, vector& coins) {
	//step1 构建dp数组
	//dp[j]的含义是使用coins中的物品(没有次数限制)装满容量为amount的背包有多少种方法
	vector dp(amount + 1, 0);
	//step2 状态转移公式
	//和0-1背包一样,dp[j] += dp[j - nums[i]]
	//step3 初始化
	dp[0] = 1;
	//step4 遍历顺序
	//注意,完全背包问题如果只是判断能够装满的话,遍历顺序可以颠倒
	//本题是组合问题,只能先遍历物品,再遍历背包
	//如果是排序问题,要先遍历背包,再遍历物品
	for (int i = 0; i < coins.size(); i++) {
		for (int j = coins[i]; j <= amount; j++) {
			dp[j] += dp[j - coins[i]];
		}
	}
	return dp[amount];
}

2.本题小节

        思考:明确本题是完全背包求解装满amount容量有多少种方法的组合问题即可,按照完全背包此种类型的套路解题即可。

        基本步骤:状态转移公式和0-1背包问题求方法次数相同,dp[j] += dp[j - coins[i]]注意求方法次数是dp[0] = 1,否则无法完成推导,注意背包容量从j = coins[i]开始,这样才能满足j >= coins[i]的条件。 

377. 组合总和 Ⅳ 

1.代码展示

//377.数组总和Ⅳ
int combinationSum4(vector& nums, int target) {
	//step1 dp[j]的含义是物品(nums元素,无限制)装满容量为j的背包的方法次数
	vector dp(target + 1, 0);
	//step2 
	//dp[j] += dp[j - nums[i]];
	//step3
	dp[0] = 1;
	//step4 本题是完全背包的排序问题,先遍历背包容量,再遍历物品
	for (int j = 0; j <= target; j++) {
		for (int i = 0; i < nums.size(); i++) {
			if (j >= nums[i] && dp[j] < INT_MAX - dp[j - nums[i]])
				dp[j] += dp[j - nums[i]];
		}
	}
	return dp[target];
}

2.本题小节

        思考:明确本题是完全背包求装满容量为target的背包有多少种方法的排列问题,根据完全背包求方法次数的第二种情况来求解。

        基本思路:和上体差不多,就是遍历顺序变了,注意状态转移方程的使用条件,dp[j] + dp[j - nums[i]]可能大于INT_MAX,会越界,因此多了一个条件。

你可能感兴趣的:(算法)