打卡 | 动态规划 - 完全背包、518. 零钱兑换 II、 377. 组合总和 Ⅳ

完全背包

相对于01背包的区别,物品有无限个,可以无限取。

01背包和完全背包唯一不同就是体现在遍历顺序上,所以本文就不去做动规五部曲了,我们直接针对遍历顺序经行分析!

01背包核心代码:

for(int i = 0; i < weight.size(); i++) { // 遍历物品
    for(int j = bagWeight; j >= weight[i]; j--) { // 遍历背包容量
        dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
    }
}

01背包内嵌的循环是从大到小遍历,为了保证每个物品仅被添加一次。

而完全背包的物品是可以添加多次的,所以要从小到大去遍历,即:

// 先遍历物品,再遍历背包
for(int i = 0; i < weight.size(); i++) { // 遍历物品
    for(int j = weight[i]; j <= bagWeight ; j++) { // 遍历背包容量
        dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
    }
}

public static int fullBag2(int m, int bagSize, int[] w, int[] v) {
        int[] dp = new int[bagSize+1];

        for (int i = 1; i <= bagSize; i++) { // 背包容量
            for (int j = 0; j < m; j++) { // 物品
                if (i - w[j] >= 0) {
                    dp[j] = Math.max(dp[i], dp[i - w[j]] + v[j]);
                }
            }
        }

        // System.out.println(Arrays.toString(dp));

        return dp[bagSize];
    }

零钱兑换 II

在这里插入图片描述

零钱兑换 可以转化成一个完全背包问题。

即, 装满 amount 大小的 “背包”,有多少种装法。

动规五部曲:

  1. dp[j]:凑成总金额 j 的货币组合数为dp[j]
  2. dp[j] += dp[j - coins[i]]
  3. dp[0] = 1,
    dp[0]一定要为1,dp[0] = 1是 递归公式的基础。如果dp[0] = 0 的话,后面所有推导出来的值都是0了。
  4. 遍历顺序:
    刚刚提到了,完全背包和01背包的区别就在于遍历方式。
    完全背包,内层也是正序遍历。

先来看 外层for循环遍历物品(钱币),内层for遍历背包(金钱总额)的情况。

for (int i = 0; i < coins.size(); i++) { // 遍历物品
    for (int j = coins[i]; j <= amount; j++) { // 遍历背包容量
        dp[j] += dp[j - coins[i]];
    }
}

假设:coins[0] = 1,coins[1] = 5。
那么就是先把1加入计算,然后再把5加入计算,得到的方法数量只有{1, 5}这种情况。而不会出现{5, 1}的情况。

所以这种遍历顺序中dp[j]里计算的是组合数!

如果把两个for交换顺序,代码如下:

for (int j = 0; j <= amount; j++) { // 遍历背包容量
    for (int i = 0; i < coins.size(); i++) { // 遍历物品
        if (j - coins[i] >= 0) dp[j] += dp[j - coins[i]];
    }
}

背包容量的每一个值,都是经过 1 和 5 的计算,包含了{1, 5} 和 {5, 1}两种情况。
此时dp[j]里算出来的就是排列数!

即,
外层遍历物品,内层遍历背包,即求组合数。
外层遍历背包,内层遍历物品,即求排列数。

  1. 举例推导dp数组
class Solution {
    public int change(int amount, int[] coins) {
        int[] dp = new int[amount+1];
        dp[0] = 1;

        for (int i=0; i<coins.length; i++) {
            for (int j=coins[i]; j<=amount; j++) {
                dp[j] += dp[j - coins[i]];
            }
        }
        return dp[amount];
    }
}

377. 组合总和 Ⅳ

在这里插入图片描述

这道题和上一题的核心思路是一样的,只不过此题的结果中需要考虑元素的顺序,那么就是求排列数。

外层遍历物品,内层遍历背包,即求组合数。
外层遍历背包,内层遍历物品,即求排列数。

那么遍历顺序就需要变一变

外层遍历背包 target,内层遍历物品(nums)

class Solution {
    public int combinationSum4(int[] nums, int target) {
        int[] dp = new int[target+1];

        dp[0] = 1;

        for (int j = 0; j <= target; j++) {
            for (int i = 0; i < nums.length; i++) {
                if (j >= nums[i]) {
                    dp[j] += dp[j - nums[i]];
                }
            }
            // System.out.println(Arrays.toString(dp));
        }

        return dp[target];
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
void welcome() { printf("**********欢迎使用管理系统*************\n"); //以不同的角色进行登录系统 printf("1.管理员身份登录\n"); printf("2.普通用户学生登录\n"); printf("3.退出\n"); printf("******************************************\n"); } //管理员的菜单界面 void mangeview() { printf("**********欢迎管理员登录********\n"); printf("-----------------1.注册学生信息------------------\n"); printf("-----------------2.输出学生信息------------------\n"); printf("-----------------3.删除学生信息------------------\n"); printf("-----------------4.修改学生信息------------------\n"); printf("-----------------5.查询学生信息------------------\n"); printf("-----------------6.学生请假和补卡------------------\n"); printf("-----------------7.排序(姓名、学号、打卡次数)--\n"); printf("-----------------8.考勤数据统计------------------\n"); printf("-----------------9.返回------o( ̄ヘ ̄o#)----\n"); //........ printf("********************************\n"); } //普通用户界面 //普通用户界面提示 void comuser(){ printf("************欢迎学生登录************\n"); printf("-----------------1.录入学生信息------------------\n"); printf("-----------------2.输出学生信息------------------\n"); printf("-----------------3.查询学生信息------------------\n"); printf("-----------------4.排序(姓名、学号、打卡次数)--\n"); printf("-----------------5.学生请假和补卡------------------\n"); printf("-----------------6.返回------o( ̄ヘ ̄o#)----\n"); printf("********************************************\n"); } 这个代码怎么描述,运用了什么函数
06-09

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值