动态规划专题讲解(二)

简介: 动态规划专题讲解(二)


多重背包


LeetCode上无对应题目,只简单介绍


1. 多重背包例题

题目

有N种物品和一个容量为 V  的背包。第i种物品最多有 M i 件可用,每件耗费的空间是C i

,价值是 W i 。求解将哪些物品装入背包可使这些物品的耗费的空间 总和不超过背包容量,且价值总和最大。


多重背包和01背包是非常像的, 为什么和01背包像呢?


每件物品最多有 M i件可用,把 M i 件摊开,其实就是一个01背包问题了。


例如:


背包最大重量为10。


物品为:


重量 价值 数量
物品0

1

15

2

物品1

3

20

3

物品2

4

30

2

问背包能背的物品最大价值是多少?


和如下情况有区别么?


重量 价值 数量
物品0

1

15

1

物品0

1

15

1

物品1

3

20

1

物品1

3

20

1

物品1

3

20

1

物品2

4

30

1

物品2

4

30

1

毫无区别,这就转成了一个01背包问题了,且每个物品只用一次。


思路

将有多件的物品展开,就可将完全背包转换成01背包


代码展示

#include 
#include 
using namespace std;
void test_multi_pack()
{
    vector weight = {1, 3, 4};
    vector value = {15, 20, 30};
    vector nums = {2, 3, 2};
    int bagWeight = 10;
    for (int i = 0; i < nums.size(); i++)
    {
        while (nums[i] > 1)
        { // nums[i]保留到1,把其他物品都展开
            weight.push_back(weight[i]);
            value.push_back(value[i]);
            nums[i]--;
        }
    }
    vector dp(bagWeight + 1, 0);
    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]);
        }
        for (int j = 0; j <= bagWeight; j++)
        {
            cout << dp[j] << " ";
        }
        cout << endl;
    }
    cout << dp[bagWeight] << endl;
}
int main()
{
    test_multi_pack();
    return 0;
}


小结

做了这些题目后,感觉在没有系统学习dp之前,抓不住重点,有时稀里糊涂ac了,但不能完整推出来。所以说,卡尔哥的专题真的很有帮助!


四、打家劫舍


打家劫舍(LeetCode-198)

题目

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。


给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。


示例 1:

输入:[1,2,3,1]
输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4 。


示例 2:

输入:[2,7,9,3,1]
输出:12
解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
     偷窃到的最高金额 = 2 + 9 + 1 = 12 。


提示:


1 <= nums.length <= 100

0 <= nums[i] <= 400

思路

五部曲


dp[i]含义


偷窃前 i 个房子(包括房子i)可以获取的最大金额

递推公式


d p [ i ] = m a x ( d p [ i − 1 ] , d p [ i − 2 ] + n u m s [ i ] )

数组初始化


dp[0]=0 dp[1]=nums[0]

遍历顺序


从前往后

代码

class Solution
{
public:
    int rob(vector &nums)
    {
        int n = nums.size();
        if (n == 1)
        {
            return nums[0];
        }
        if (n == 2)
        {
            return max(nums[0], nums[1]);
        }
        vector dp(2);
        dp[0] = nums[0];
        dp[1] = max(nums[0], nums[1]);
        int result;
        for (int i = 2; i < n; i++)
        {
            result = max(dp[1], dp[0] + nums[i]);
            dp[0] = dp[1];
            dp[1] = result;
        }
        return result;
    }
};


打家劫舍Ⅱ(LeetCode-213)

题目

你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。


给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,今晚能够偷窃到的最高金额。


示例 1:

输入:nums = [2,3,2]
输出:3
解释:你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。


示例 2:

输入:nums = [1,2,3,1]
输出:4
解释:你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4 。


示例 3:

输入:nums = [1,2,3]
输出:3


提示:


1 <= nums.length <= 100

0 <= nums[i] <= 1000

思路

当房间数不超过二,不需要考虑首尾


超过二时,因为不能同时偷首尾房间,所以可以分两种情况考虑


不偷最后一间情况:盗窃范围 n u m s [ 0 : n − 2 ]

不偷第一间情况:盗窃范围 n u m s [ 1 : n − 1 ]

二者取较大值


代码展示

class Solution
{
public:
    int rob(vector &nums)
    {
        int n = nums.size();
        if (n == 1)
        {
            return nums[0];
        }
        int left = robRange(nums, 0, n - 2);
        int right = robRange(nums, 1, n - 1);
        return max(left, right);
    }
    int robRange(vector &nums, int start, int end)
    {
        if (start == end)
        {
            return nums[start];
        }
        vector dp(nums.size());
        dp[start] = nums[start];
        dp[start + 1] = max(nums[start], nums[start + 1]);
        for (int i = start + 2; i <= end; i++)
        {
            dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]);
        }
        return dp[end];
    }
};


打家劫舍Ⅲ(LeetCode-337)

题目

小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为 root 。


除了 root 之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果 两个直接相连的房子在同一天晚上被打劫 ,房屋将自动报警。


给定二叉树的 root 。返回 在不触动警报的情况下 ,小偷能够盗取的最高金额 。


示例 1:


输入: root = [3,2,3,null,3,null,1]
输出: 7 
解释: 小偷一晚能够盗取的最高金额 3 + 3 + 1 = 7


示例 2:


输入: root = [3,4,5,1,3,null,1]
输出: 9
解释: 小偷一晚能够盗取的最高金额 4 + 5 = 9


提示:


树的节点数在 [1, 104] 范围内

0 <= Node.val <= 104

思路

树形数组


确定递归函数参数与返回值


返回偷和不偷两种状态下获得的金钱。下标0表示不偷当前节点获得的最大金额,下标1表示偷当前节点获得的最大金额

确定终止条件


遇到空节点,肯定返回 { 0 , 0 }

确定遍历顺序


必须后序遍历,因为要通过递归函数返回值后考虑

确定单层逻辑


如果偷当前节点


左右孩子不能偷,即左右孩子各取下标0的值相加

v a l 1 = c u r . v a l + l e f t [ 0 ] + r i g h t [ 0 ]

如果不偷当前节点


左右孩子可以考虑偷,但到底偷不偷还是要判断

v a l 2 = m a x ( l e f t [ 0 ] , l e f t [ 1 ] ) + m a x ( r i g h t [ 0 ] , r i g h t [ 1 ] )

测试用例



代码展示

class Solution
{
public:
    int rob(TreeNode *root)
    {
        vector result = robTree(root);
        return max(result[0], result[1]);
    }
    vector robTree(TreeNode *cur)
    {
        if (!cur)
        {
            return {0, 0};
        }
        vector curleft = robTree(cur->left);
        vector curright = robTree(cur->right);
        int val1 = cur->val + curleft[0] + curright[0];
        int val2 = max(curleft[0], curleft[1]) + max(curright[0], curright[1]);
        return {val2, val1};
    }
};
目录
相关文章
|
2天前
|
人工智能 自动驾驶 大数据
预告 | 阿里云邀您参加2024中国生成式AI大会上海站,马上报名
大会以“智能跃进 创造无限”为主题,设置主会场峰会、分会场研讨会及展览区,聚焦大模型、AI Infra等热点议题。阿里云智算集群产品解决方案负责人丛培岩将出席并发表《高性能智算集群设计思考与实践》主题演讲。观众报名现已开放。
|
18天前
|
存储 人工智能 弹性计算
阿里云弹性计算_加速计算专场精华概览 | 2024云栖大会回顾
2024年9月19-21日,2024云栖大会在杭州云栖小镇举行,阿里云智能集团资深技术专家、异构计算产品技术负责人王超等多位产品、技术专家,共同带来了题为《AI Infra的前沿技术与应用实践》的专场session。本次专场重点介绍了阿里云AI Infra 产品架构与技术能力,及用户如何使用阿里云灵骏产品进行AI大模型开发、训练和应用。围绕当下大模型训练和推理的技术难点,专家们分享了如何在阿里云上实现稳定、高效、经济的大模型训练,并通过多个客户案例展示了云上大模型训练的显著优势。
|
22天前
|
存储 人工智能 调度
阿里云吴结生:高性能计算持续创新,响应数据+AI时代的多元化负载需求
在数字化转型的大潮中,每家公司都在积极探索如何利用数据驱动业务增长,而AI技术的快速发展更是加速了这一进程。
|
13天前
|
并行计算 前端开发 物联网
全网首发!真·从0到1!万字长文带你入门Qwen2.5-Coder——介绍、体验、本地部署及简单微调
2024年11月12日,阿里云通义大模型团队正式开源通义千问代码模型全系列,包括6款Qwen2.5-Coder模型,每个规模包含Base和Instruct两个版本。其中32B尺寸的旗舰代码模型在多项基准评测中取得开源最佳成绩,成为全球最强开源代码模型,多项关键能力超越GPT-4o。Qwen2.5-Coder具备强大、多样和实用等优点,通过持续训练,结合源代码、文本代码混合数据及合成数据,显著提升了代码生成、推理和修复等核心任务的性能。此外,该模型还支持多种编程语言,并在人类偏好对齐方面表现出色。本文为周周的奇妙编程原创,阿里云社区首发,未经同意不得转载。
|
7天前
|
人工智能 自然语言处理 前端开发
100个降噪蓝牙耳机免费领,用通义灵码从 0 开始打造一个完整APP
打开手机,录制下你完成的代码效果,发布到你的社交媒体,前 100 个@玺哥超Carry、@通义灵码的粉丝,可以免费获得一个降噪蓝牙耳机。
3761 13
|
26天前
|
缓存 监控 Linux
Python 实时获取Linux服务器信息
Python 实时获取Linux服务器信息
|
12天前
|
人工智能 自然语言处理 前端开发
什么?!通义千问也可以在线开发应用了?!
阿里巴巴推出的通义千问,是一个超大规模语言模型,旨在高效处理信息和生成创意内容。它不仅能在创意文案、办公助理、学习助手等领域提供丰富交互体验,还支持定制化解决方案。近日,通义千问推出代码模式,基于Qwen2.5-Coder模型,用户即使不懂编程也能用自然语言生成应用,如个人简历、2048小游戏等。该模式通过预置模板和灵活的自定义选项,极大简化了应用开发过程,助力用户快速实现创意。
|
14天前
|
人工智能 自然语言处理 前端开发
用通义灵码,从 0 开始打造一个完整APP,无需编程经验就可以完成
通义灵码携手科技博主@玺哥超carry 打造全网第一个完整的、面向普通人的自然语言编程教程。完全使用 AI,再配合简单易懂的方法,只要你会打字,就能真正做出一个完整的应用。本教程完全免费,而且为大家准备了 100 个降噪蓝牙耳机,送给前 100 个完成的粉丝。获奖的方式非常简单,只要你跟着教程完成第一课的内容就能获得。
6187 10
|
8天前
|
人工智能 C++ iOS开发
ollama + qwen2.5-coder + VS Code + Continue 实现本地AI 辅助写代码
本文介绍在Apple M4 MacOS环境下搭建Ollama和qwen2.5-coder模型的过程。首先通过官网或Brew安装Ollama,然后下载qwen2.5-coder模型,可通过终端命令`ollama run qwen2.5-coder`启动模型进行测试。最后,在VS Code中安装Continue插件,并配置qwen2.5-coder模型用于代码开发辅助。
618 4
|
10天前
|
云安全 人工智能 自然语言处理