动态规划模式

        动态规划(Dynamic Programming, DP)是一种解决复杂问题的算法设计技术,它通过将大问题分解为小问题,并利用小问题的解决方案来构造大问题的解决方案,从而避免了重复计算。动态规划通常用于具有“最优子结构”和“重叠子问题”特征的问题。

动态规划的基本步骤

  1. 定义状态:明确问题的状态表示。即如何用状态表示当前的子问题。
  2. 状态转移方程:根据问题的结构,找到从一个状态转移到另一个状态的方式。
  3. 初始化:为基础情况设置初始值。
  4. 计算顺序:确定计算的顺序,从最小的子问题开始逐步计算到原问题。
  5. 答案提取:从动态规划表中提取最终答案。

动态规划的典型应用场景

  • 最短路径问题(如 Dijkstra、Floyd 算法)。
  • 背包问题(如 0/1 背包、完全背包)。
  • 字符串匹配问题(如最长公共子序列、编辑距离)。
  • 最优子结构问题(如矩阵链乘法问题、切割钢条问题)。

动态规划的分类

动态规划的算法通常可以分为以下两种类型:

  1. 自顶向下的递归式动态规划(Top-Down with Memoization):

        使用递归进行问题的求解,并通过记忆化(Memoization)保存已计算的结果,避免重复计算。

  1. 自底向上的迭代式动态规划(Bottom-Up with Tabulation):

        通过迭代从最小子问题开始,逐步解决更大的子问题,直到得到最终结果。

动态规划的三大特点

  1. 最优子结构:问题的最优解可以通过子问题的最优解来构造。例如,最长公共子序列问题的最优解可以通过子问题的解来构造。
  2. 重叠子问题:不同的子问题可能会多次出现,因此可以通过记忆化来存储已解决的子问题,避免重复计算。
  3. 状态转移:通过当前状态和已解决的子问题来推导出下一个状态。

动态规划的经典问题

1. 0/1 背包问题

问题描述:

  • 有一个背包,最多可以容纳重量为 W 的物品。
  • 有 n 个物品,每个物品的重量是 w[i],价值是 v[i]。
  • 问:如何选择物品,使得背包的总价值最大,且总重量不超过 W?

动态规划解法:

  • 定义状态 dp[i][j]:表示前 i 个物品,背包容量为 j 时的最大价值。
  • 状态转移方程:
    • 如果不选择第 i 个物品:dp[i][j] = dp[i-1][j]
    • 如果选择第 i 个物品:dp[i][j] = dp[i-1][j-w[i]] + v[i]
    • 最终的状态转移方程为:dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]] + v[i])
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int knapsack(int W, vector<int>& w, vector<int>& v, int n) {
    // dp[i][j]表示前i个物品,容量为j时的最大价值
    vector<vector<int>> dp(n + 1, vector<int>(W + 1, 0));

    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= W; j++) {
            if (w[i - 1] <= j) {
                // 当前物品不放入或放入两种选择的最大值
                dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i - 1]] + v[i - 1]);
            } else {
                dp[i][j] = dp[i - 1][j]; // 当前物品不能放入
            }
        }
    }
    return dp[n][W]; // 返回最大价值
}

int main() {
    int W = 10; // 背包容量
    vector<int> w = {2, 3, 4, 5}; // 物品重量
    vector<int> v = {3, 4, 5, 6}; // 物品价值
    int n = w.size();

    cout << "Max value in knapsack: " << knapsack(W, w, v, n) << endl;
    return 0;
}

输出:

Max value in knapsack: 7

2. 最长公共子序列问题

问题描述:

  • 给定两个字符串 s1 和 s2,求它们的最长公共子序列(LCS)。

动态规划解法:

  • 定义状态 dp[i][j]:表示 s1[0...i-1] 和 s2[0...j-1] 的最长公共子序列长度。
  • 状态转移方程:
    • 如果 s1[i-1] == s2[j-1],那么 dp[i][j] = dp[i-1][j-1] + 1
    • 否则,dp[i][j] = max(dp[i-1][j], dp[i][j-1])
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int longestCommonSubsequence(string s1, string s2) {
    int m = s1.size(), n = s2.size();
    vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));

    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            if (s1[i - 1] == s2[j - 1]) {
                dp[i][j] = dp[i - 1][j - 1] + 1;
            } else {
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
            }
        }
    }
    return dp[m][n]; // 返回最长公共子序列长度
}

int main() {
    string s1 = "abcde";
    string s2 = "ace";

    cout << "Length of Longest Common Subsequence: " << longestCommonSubsequence(s1, s2) << endl;
    return 0;
}

输出:

Length of Longest Common Subsequence: 3

3. 斐波那契数列

斐波那契数列是经典的动态规划问题。其定义是:

  • F(0) = 0
  • F(1) = 1
  • F(n) = F(n-1) + F(n-2)

动态规划解法通过迭代避免了递归中的重复计算。

#include <iostream>
using namespace std;

int fib(int n) {
    if (n <= 1) return n;
    
    int prev2 = 0, prev1 = 1;
    for (int i = 2; i <= n; i++) {
        int curr = prev1 + prev2;
        prev2 = prev1;
        prev1 = curr;
    }
    return prev1;
}

int main() {
    int n = 10;
    cout << "Fibonacci of " << n << " is " << fib(n) << endl;
    return 0;
}

输出:

Fibonacci of 10 is 55

总结

        动态规划是一种通过将问题分解成小问题并利用已解决的小问题来避免重复计算的技术。其核心思想是使用状态表示问题的不同阶段,并通过状态转移方程来递推求解。在实际应用中,动态规划非常适用于具有“最优子结构”和“重叠子问题”特征的问题,常见的问题有背包问题、最长公共子序列、矩阵链乘法等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/947421.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Github拉取项目报错解决

前言 昨天在拉取github上面的项目报错了&#xff0c;有好几个月没用github了&#xff0c;命令如下&#xff1a; git clone gitgithub.com:zhszstudy/git-test.git报错信息&#xff1a; ssh: connect to host github.com port 22: Connection timed out fatal: Could not rea…

TypeScript 常用类型

文章目录 1. 类型注解2. 原始类型3. 数组类型4. 联合类型5. 类型别名6. 函数类型7. 对象类型8. 接口类型8.1 接口声明8.2 接口继承 9. 元组类型10. 类型断言11. 字面量类型12. 枚举类型12.1 数字枚举12.2 字符串枚举 13. any 类型14. typeof 运算符 1. 类型注解 前言&#xff1…

ARM200~500部署

前提&#xff1a;数据库已经安装好&#xff0c;并且正常运行 1.修改hostname,将里面的AR-A 改为hzx vi /etc/hostname 2.重启网络服务 sudo systemctl restart NetworkManager 3.修改community-admin.service 文件&#xff0c;更改小区名称和IP&#xff0c;并将文件上传到/…

Linux buildroot和ubuntu的异同点

Buildroot 和 Ubuntu 都是 Linux 系统的操作环境,但它们的设计理念和使用场景有很大的不同。 一、定义与目标 Buildroot Buildroot 是一个用于生成嵌入式 Linux 系统的工具集,专注于交叉编译和构建嵌入式设备的最小 Linux 环境。它的目标是为嵌入式系统提供定制化和优化的…

从0开始的opencv之旅(1)cv::Mat的使用

目录 Mat 存储方法 创建一个指定像素方式的图像。 尽管我们完全可以把cv::Mat当作一个黑盒&#xff0c;但是笔者的建议是仍然要深入理解和学习cv::Mat自身的构造逻辑和存储原理&#xff0c;这样在查找问题&#xff0c;或者是遇到一些奇奇怪怪的图像显示问题的时候能够快速的想…

免登录游客卡密发放系统PHP网站源码

源码介绍&#xff1a; 这是一个简单易用的卡密验证系统&#xff0c;主要功能包括&#xff1a; 卡密管理和验证&#xff0c;多模板支持&#xff0c;响应式设计&#xff0c;验证码保护&#xff0c;防刷机制&#xff0c;简洁的用户界面&#xff0c; 支持自定义模板&#xff0c;移…

LeetCode - 初级算法 数组(旋转数组)

旋转数组 这篇文章讨论如何通过编程实现数组元素的旋转操作。 免责声明:本文来源于个人知识与公开资料,仅用于学术交流。 描述 给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。 示例: 输入: nums = [1,2,3,

BOC调制信号matlab性能仿真分析,对比功率谱,自相关性以及抗干扰性

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) 2.算法运行软件版本 matlab2022a 3.部分核心程序 &#xff08;完整版代码包含详细中文注释和操作步骤视频&#xff09…

【从零开始入门unity游戏开发之——C#篇41】C#迭代器(Iterator)——自定义类实现 foreach 操作

文章目录 前言一、什么是迭代器&#xff1f;二、标准迭代器的实现方法1、自定义一个类CustomList2、让CustomList继承IEnumerable接口3、再继承IEnumerator接口4、完善迭代器功能5、**foreach遍历的本质**&#xff1a;6、在Reset方法里把光标复原 三、用yield return语法糖实现…

WordPress新安装只安装主题后发现只有首页能打开,其他路由页面都是404,并且Elementor都打不开

找到wordpress安装路径的这个文件&#xff0c;有发现里面没有内容&#xff0c;添加下面内容保存&#xff0c;重启服务器即可 # BEGIN WordPress <IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteRule ^index\.php$ – [L] RewriteCond %{REQUEST_FILEN…

uniapp中使用ruoyiPlus中的加密使用(crypto-js)

package.json中添加 "crypto-js": "^4.2.0", "jsencrypt": "^3.3.2",但是vue2中使用 import CryptoJS from cryptojs; 这一步就会报错 参照 参照这里&#xff1a;vue2使用CryptoJS实现信息加解密 根目录下的js文档中新增一个AESwork.…

无需训练!多提示视频生成最新SOTA!港中文腾讯等发布DiTCtrl:基于MM-DiT架构

文章链接&#xff1a;https://arxiv.org/pdf/2412.18597 项目链接&#xff1a;https://github.com/TencentARC/DiTCtrl 亮点直击 DiTCtrl&#xff0c;这是一种基于MM-DiT架构的、首次无需调优的多提示视频生成方法。本文的方法结合了新颖的KV共享机制和隐混合策略&#xff0c;使…

RabbitMQ基础篇之快速入门

文章目录 一、目标需求二、RabbitMQ 控制台操作步骤1.创建队列2.交换机概述3.向交换机发送消息4.结果分析5.消息丢失原因 三、绑定交换机与队列四、测试消息发送五、消息查看六、结论 一、目标需求 新建队列&#xff1a;创建 hello.queue1 和 hello.queue2 两个队列。消息发送…

ESP32S3 + IDF 5.2.2 扫描WiFi

ESP32S3 IDF 5.2.2 扫描WiFi 目录 1 资料 2 通过Wi-Fi库扫描附近的网络 2.1 通过idf命令创建工程 2.2 编写测试用例 2.3 优化测试用例 3 小结 1 资料 在ESP平台基于IDF开发WiFi相关功能&#xff0c;主要就是基于IDF的Wi-Fi库进行二次开发。可供参考的官方资料&#xff…

2025-1-2-sklearn学习(30)模型选择与评估-验证曲线: 绘制分数以评估模型 真珠帘卷玉楼空,天淡银河垂地。

文章目录 sklearn学习(30) 模型选择与评估-验证曲线: 绘制分数以评估模型30.1. 验证曲线30.2. 学习曲线 sklearn学习(30) 模型选择与评估-验证曲线: 绘制分数以评估模型 文章参考网站&#xff1a; https://sklearn.apachecn.org/ 和 https://scikit-learn.org/stable/ 每种估…

统信系统设置代理的问题

统信系统设置代理的问题 问题表现方式一方式二 问题表现 统信系统下有系统代理和应用代理两个代理。设置系统代理时&#xff0c;git不能经过代理拉取代码。但是设置应用代理时&#xff0c;可以用git通过代理拉代码。 这是系统代理&#xff0c;在这里设置 ip 端口&#xff0c;…

STM32-笔记19-串口打印功能

复制项目文件夹03-流水灯&#xff0c;重命名为19-串口打印功能 打开项目 在主函数中&#xff0c;添加头文件、和串口初始化函数&#xff08;设置波特率&#xff09;和输出函数&#xff0c;如图所示&#xff1a; 软件部分就设置好了 下面是硬件部分 接线&#xff1a;使用USB…

JavaWeb——MySQL-DML(1/3)-添加数据insert(DML 操作概述、INSERT 语句插入数据、语句演示、总结)

目录 DML 操作概述 INSERT 语句插入数据 INSERT 语句基础语法 INSERT 语句演示 注意事项 总结 DML 操作概述 DML 简介 DML&#xff08;Data Manipulation Language&#xff09;即数据操作语言&#xff0c;用于对数据库表中的数据进行增删改操作&#xff0c;包括添加数据&…

Docker图形化界面工具Portainer最佳实践

前言 安装Portainer 实践-基于Portainer安装redis-sentinel部署 Spring Boot集成Redis Sentinel 前言 本篇文章笔者推荐一个笔者最常用的docker图形化管理工具——Portainer。 安装Portainer 编写docker-compose文件 Portainer部署的步骤比较简单&#xff0c;我们还是以…

Wonder Dynamics技术浅析(五):虚拟场景描述解析

虚拟场景描述解析模块是 Wonder Dynamics 平台的核心组件之一&#xff0c;其主要功能是将用户输入的自然语言场景描述转换为机器可理解的语义表示&#xff0c;为后续的虚拟场景生成提供基础数据。 一、文本预处理&#xff08;Text Preprocessing&#xff09; 1. 目标: 对用户…