算法--动态规划

news/2024/5/20 20:24:32

动态规划(Dynamic Programming, DP)是一种算法设计技巧,用于解决具有重叠子问题和最优子结构性质的问题。通过将原问题分解为相对简单的子问题的方式来求解复杂问题,动态规划避免了计算重复子问题,从而提高了算法的效率。

动态规划的关键特点包括:

  1. 重叠子问题:在求解过程中,相同的子问题会被多次计算。动态规划通过存储这些子问题的解(通常是在一个表格中),每个子问题只解决一次,以避免不必要的计算。
  2. 最优子结构:一个问题的最优解包含其子问题的最优解。这意味着可以通过组合子问题的最优解来构造原问题的最优解。
  3. 状态转移方程:动态规划算法的核心,它描述了问题的状态如何从一个状态转移到另一个状态。状态转移方程通常取决于当前决策和相应的子问题解。

动态规划的步骤通常包括:

  1. 定义状态:确定问题的状态,以及状态之间的关系。
  2. 确定状态转移方程:找出状态之间如何转移的规则。
  3. 初始化条件:确定初始状态的值。
  4. 计算顺序:确定计算状态的顺序,确保在计算当前状态时,所需的子状态已经计算过。
  5. 构造最优解:根据计算出的状态值,构造问题的最优解。
    动态规划广泛应用于各种领域,包括但不限于:
  • 最短路径问题:如Dijkstra算法和Floyd-Warshall算法。
  • 序列对齐问题:如生物信息学中的序列对齐。
  • 资源分配问题:如背包问题。
  • 字符串编辑距离:如计算两个字符串之间的最小编辑距离。
  • 最长公共子序列:找出两个序列共有的最长子序列。

动态规划是解决优化问题的强大工具,但它要求问题具有重叠子问题和最优子结构的特性。正确识别和定义这些特性是应用动态规划成功的关键。

0-1背包问题
0-1背包问题是动态规划中的经典问题。给定一组物品,每种物品都有自己的重量和价值,在限定的总重量内,选择其中若干个(也即每种物品可以选择0个或1个),设计选择方案使得物品的总价值最高。
以下是使用动态规划解决0-1背包问题的C语言实现:

#include <stdio.h>
#include <stdlib.h>// 返回两个整数中的最大值
int max(int a, int b) {return (a > b) ? a : b;
}// 动态规划解决0-1背包问题
// 参数:W为背包最大容量,wt为物品重量数组,val为物品价值数组,n为物品数量
int knapSack(int W, int wt[], int val[], int n) {int i, w;// 创建一个二维数组dp,其中dp[i][w]表示在前i个物品中,能够装入容量为w的背包中的最大价值int **dp = (int **)malloc((n + 1) * sizeof(int *));for (i = 0; i <= n; i++) {dp[i] = (int *)malloc((W + 1) * sizeof(int));}// 填充表格for (i = 0; i <= n; i++) {for (w = 0; w <= W; w++) {if (i == 0 || w == 0)dp[i][w] = 0;else if (wt[i - 1] <= w)dp[i][w] = max(val[i - 1] + dp[i - 1][w - wt[i - 1]], dp[i - 1][w]);elsedp[i][w] = dp[i - 1][w];}}// 存储结果int result = dp[n][W];// 释放dp数组for (i = 0; i <= n; i++) {free(dp[i]);}free(dp);return result;
}// 测试代码
int main() {int val[] = {60, 100, 120};int wt[] = {10, 20, 30};int W = 50;int n = sizeof(val) / sizeof(val[0]);printf("背包中物品的最大价值为:%d", knapSack(W, wt, val, n));return 0;
}

这段代码首先定义了一个max函数,用于返回两个整数中的最大值。knapSack函数是动态规划解决0-1背包问题的核心,它创建了一个二维数组dp,其中dp[i][w]表示在前i个物品中,能够装入容量为w的背包中的最大价值。通过填充这个表格,最终在dp[n][W]中得到了在给定物品和背包容量限制下的最大价值。最后,函数释放了dp数组所占用的内存,并返回了最大价值结果。

最长公共子序列问题
最长公共子序列(Longest Common Subsequence, LCS)问题是寻找两个序列共有的最长子序列的长度,这个子序列不需要在原序列中是连续的。以下是使用动态规划解决最长公共子序列问题的C语言实现:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 返回两个整数中的最大值
int max(int a, int b) {return (a > b) ? a : b;
}// 动态规划解决LCS问题
int lcs(char *X, char *Y, int m, int n) {int L[m+1][n+1];int i, j;// 构建L[m+1][n+1],以便保存LCS的长度for (i = 0; i <= m; i++) {for (j = 0; j <= n; j++) {if (i == 0 || j == 0)L[i][j] = 0;else if (X[i-1] == Y[j-1])L[i][j] = L[i-1][j-1] + 1;elseL[i][j] = max(L[i-1][j], L[i][j-1]);}}// L[m][n]包含了X[0..m-1]和Y[0..n-1]的LCS的长度return L[m][n];
}// 打印LCS,这是一个辅助函数
void printLCS(char *X, char *Y, int m, int n) {int index = lcs(X, Y, m, n);char lcs[index+1];lcs[index] = '\0'; // 设置字符串的终止符int i = m, j = n;while (i > 0 && j > 0) {if (X[i-1] == Y[j-1]) {lcs[index-1] = X[i-1]; // 如果当前字符在LCS中i--; j--; index--;     // 减少值}else if (L[i-1][j] > L[i][j-1])i--;elsej--;}// 打印LCSprintf("LCS of %s and %s is %s\n", X, Y, lcs);
}// 测试代码
int main() {char X[] = "AGGTAB";char Y[] = "GXTXAYB";int m = strlen(X);int n = strlen(Y);printf("Length of LCS is %d\n", lcs(X, Y, m, n));// 如果需要打印LCS,取消注释下面的行// printLCS(X, Y, m, n);return 0;
}

这段代码首先定义了一个max函数,用于返回两个整数中的最大值。lcs函数是动态规划解决LCS问题的核心,它创建了一个二维数组L,其中L[i][j]表示字符串X[0…i-1]和Y[0…j-1]的LCS的长度。通过填充这个表格,最终在L[m][n]中得到了两个字符串的LCS的长度。

请注意,上述代码中的printLCS函数用于打印LCS,但由于它依赖于L数组,而L数组在lcs函数中是局部变量,直接使用printLCS函数可能会导致编译错误。为了使printLCS函数正常工作,需要对代码进行适当的修改,以便能够访问或重新计算L数组的值。这里提供的printLCS函数主要是为了展示如何根据L数组回溯找到LCS,实际使用时需要注意这一点。


http://www.mrgr.cn/p/15170186

相关文章

如何让加快OpenHarmony编译速度?

OpenHarmony 有两种编译方式&#xff0c;一种是通过 hb 工具编译&#xff0c;一种是通过 build.sh 脚本编译。本文笔者将提升 build.sh 方式编译速度的方法整理如下&#xff1a; 因为笔者只用 build.sh 脚本编译&#xff0c;没用过 hb 工具&#xff0c;好像下面的选项也可以用于…

容灾演练双月报|郑大一附院数据级容灾演练切换

了解更多灾备行业动态 守护数字化时代业务连续 目录 CONTENTS 01 灾备法规政策 02 热点安全事件 03 容灾演练典型案例 01 灾备法规政策 3月19日&#xff0c;工信部发布《工业和信息化部办公厅关于做好2024年信息通信业安全生产和网络运行安全工作的通知》。明确提出“…

llama.cpp制作GGUF文件及使用

llama.cpp的介绍 llama.cpp是一个开源项目&#xff0c;由Georgi Gerganov开发&#xff0c;旨在提供一个高性能的推理工具&#xff0c;专为在各种硬件平台上运行大型语言模型&#xff08;LLMs&#xff09;而设计。这个项目的重点在于优化推理过程中的性能问题&#xff0c;特别是…

我们的小程序每天早上都白屏,真相是。。。

大家好&#xff0c;我是程序员鱼皮。最近我们在内测一款面试刷题小程序&#xff0c;没错&#xff0c;就是之前倒下的 “面试鸭”&#xff01; 在我们的内测交流群中&#xff0c;每天早上都会有同学反馈&#xff1a;打开小程序空白&#xff0c;没任何内容且登录不上。 然后过了…

开源离线AI笔记应用

前言 Reor 是一款人工智能驱动的桌面笔记应用程序&#xff0c;它能自动链接相关笔记、回答笔记中的问题并提供语义搜索。所有内容都存储在本地&#xff0c;支持 Windows、Linux 和 MacOS。Reor 站在 Ollama、Transformers.js 和 LanceDB 等巨头的肩膀上&#xff0c;使 LLM 和嵌…

iceoryx源码阅读(二)——共享内存管理

目录1 共享内存模型2 获取共享内存2.1 MemoryManager::getChunk2.2 MemPool::getChunk3 释放共享内存3.1 SharedChunk::freeChunk3.2 MemPool::freeChunk4 总结 基于共享内存通信的核心在于共享内存的管理,包括共享内存的分配、释放。 1 共享内存模型 iceoryx先将整块共享内存…

iceoryx源码阅读(一)——全局概览

一、什么是iceoryx iceoryx是一套基于共享内存实现的进程间通信组件。 二、源码结构 iceoryx源码包括若干工程,整理如下表所示:下图展示了主要项目之间的依赖(FROM:iceoryx(冰羚)-Architecture):三、iceoryx应用程序结构 iceoryx应用程序有三类进程,分别为Publisher、Su…

Linux字符设备驱动(一) - 框架

字符设备是Linux三大设备之一(另外两种是块设备&#xff0c;网络设备)&#xff0c;字符设备就是字节流形式通讯的I/O设备,绝大部分设备都是字符设备&#xff0c;常见的字符设备包括鼠标、键盘、显示器、串口等等&#xff0c;当我们执行ls -l /dev的时候&#xff0c;就能看到大量…

1.4 初探JdbcTemplate操作

实战目的 掌握Spring框架中JdbcTemplate的使用&#xff0c;实现对数据库的基本操作。理解数据库连接池的工作原理及其在实际开发中的重要性。通过实际操作&#xff0c;加深对Spring框架中ORM&#xff08;对象关系映射&#xff09;的理解。 关键技术点 JdbcTemplate操作&…

重发布和路由策略

重发布 在同一个网络拓扑结构中&#xff0c;如果存在多种不同的路由协议&#xff0c;由于不同路由协议的机理各有不同&#xff0c;对路由的处理也不相同&#xff0c;这就在网络中造成了路由信息的隔离&#xff0c;在路由协议的边界设备上&#xff0c;将某种路由协议的路由信息引…

Java中的线程

一、创建线程的几种方式&#xff1f; ① 通过继承Thread类并重写run方法 &#xff0c;实现简单但不可以继承其他类 Thread底层也是实现了Runnable接口&#xff0c;重写的是run而不是start方法 ②实现Runnable接口并重写run方法&#xff0c; 避免了单继承的局限性&#xff…

PVE安装Windows 95报错 while initializing device IOS

安装Win95重启后报错信息如下图,重启一直报错 while initializing device IOS,查了下报错原因说是 CPU频率太高导致,需要安装AMDK6UPD.EXE补丁包 下载地址 https://zhangka.lanzouw.com/igW0S1y8p5pe 打补丁操作流程: 1)将下载的iso文件加载到新光盘中 2)重启到dos环境…

迅饶科技 X2Modbus 网关 AddUser 任意用户添加漏洞复现

0x01 产品简介 X2Modbus是上海迅饶自动化科技有限公司Q开发的一款功能很强大的协议转换网关, 这里的X代表各家不同的通信协议, 2是T0的谐音表示转换, Modbus就是最终支持的标准协议是Modbus协议。用户可以根据现场设备的通信协议进行配置,转成标准的Modbus协议。在PC端仿真…

# IDEA 复制项目 Module 出现 不同模块下的 Product 类报错

IDEA 复制项目 Module 出现 不同模块下的 Product 类报错 我们 用 IDEA 复制项目 Module 出现 不同模块下的 Product 类报错&#xff0c;发现复制的 module 名称没有改变或者 java 文件夹后面还有原项目 source root 字样&#xff0c;maven 父子项目没有标识等问题。 解决方法…

【前端】实现表格简单操作

简言 表格合并基础篇 本篇是在上一章的基础上实现&#xff0c;实现了的功能有添加行、删除行、逆向选区、取消合并功能。 功能实现 添加行 添加行分为在上面添加和在下面追加行。 利用 insertAdjacentElement 方法实现&#xff0c;该方法可以实现从前插入元素和从后插入元…

12 华三的二层链路聚合

12 华三的二层链路聚合 配置思路 1. 配置二层静态聚合组 (1) 进入系统视图。 system-view (2) 创建二层聚合接口&#xff0c;并进入二层聚合接口视图。 interface bridge-aggregation interface-number [ lite ] 创建二层聚合接口后&#xff0c;系统将自动生成…

苍穹外卖Day06笔记

疯玩了一个月&#xff0c;效率好低&#xff0c;今天开始捡起来苍穹外卖~ 1. 为什么不需要单独引入HttpClient的dependency&#xff1f; 因为我们在sky-common的pom.xml中已经引入了aliyun-sdk-oss的依赖&#xff0c;而这个依赖低层就引入了httpclinet的依赖&#xff0c;根据依…

Linux 文件

文章目录 文件操作回顾(C/C)系统调用接口 管理文件认识一切皆文件C/C的文件操作函数与系统调用接口的关系……重定向与缓冲区 -- 认识重定向与缓冲区 -- 理解使用重定向缓冲区实现一个简单的Shell(加上重定向)标准输出和标准错误(在重定向下的意义) 磁盘文件磁盘存储文件操作系…

docker-compose安装es+kibana 8.12.2

小伙伴们&#xff0c;你们好&#xff0c;我是老寇&#xff0c;我又回来辣&#xff0c;几个月不见甚是想念啊&#xff01;&#xff01;&#xff01; 因云平台需要改造&#xff0c;es7升级为es8&#xff0c;所以记录一下&#xff0c;es8需要开启ssl认证&#xff0c;需要配置证书…

第147天:免杀对抗-C2远控篇CC++ShellCode定性分析生成提取Loader加载模式编译执行

https://blog.csdn.net/qq_29948489/article/details/136180966 #C2远控-ShellCode-认知&环境 1.创建工程时关闭SDL检查 2.属性->C/C++->代码生成->运行库->多线程 (/MT)如果是debug则设置成MTD 3.属性->C/C++->代码生成->禁用安全检查GS 4.关闭生成清…