C++ 动态规划

文章目录

  • 一、简介
  • 二、举个栗子
    • 2.1斐波那契数列
    • 2.2最短路径(DFS)
  • 参考资料

一、简介

感觉动态规划非常的实用,因此这里整理一下相关资料。动态规划(Dynamic Programming):简称 DP,是一种优化算法,它特别适合去优化一些问题,如最短路径等(设计到最小化以及最大化的问题,都可以考虑该方法),它具有通用性。通俗来讲,可以将其视为一种穷举搜索算法,但是不同于穷举算法,它会避免许多无意义的重复操作,从而节省时间,因此也可以将其描述为“谨慎的蛮力”。

tips:动态规划一词最早由理查德·贝尔曼于 1957 年在其著作《动态规划(Dynamic Programming)》一书中提出。这里的 Programming 并不是编程的意思,而是指一种[表格处理方法],即将每一步计算的结果存储在表格中,供随后的计算查询使用,据说是最早用于处理火车的规划问题。还有另一个原因就是,本来贝尔曼想以“研究(research)”之类的词进行命名,但是国防部的官员对“研究”一词极为恐惧和厌恶,因此就采用了Programming一词(折中方案)。

DP问题存在这样一个通用的框架:

  1. 记忆化处理(记录每次计算的结果)。
  2. 找出子问题(它往往与其他问题有所关联,其结果可以被重复使用,注:子问题的依赖关系应是非循环的)。
  3. 穷举所有可能的结果(也就是,如最短路径),有的算法不需要这一步处理。

因此DP问题也可以被描述为一个:递归+记忆化处理+猜(可能存在)的过程,它的计算时间是子问题数量*每个子问题所花费的时间。当然一句话的概况往往是有形而无用的,还是需要多结合实际情况去感受,因此可以以一些例子来进一步学习。

二、举个栗子

2.1斐波那契数列

1,1,2,3,5,8,13,21,34,55,89……

首先我们可以写一个原始的版本(递归):

#include <iostream>
#include <unordered_map>int f(int n)
{if (n < 2)return 1;elsereturn f(n - 1) + f(n - 2);
}int main(int argc, char* argv[])
{// -------------------------动态规划---------------------------// 斐波那契数列int n = 7;		//以0为起始std::cout << "计算结果:" << f(n) << std::endl;std::cout << "计算结束!" << std::endl;return 0;
}

在这里插入图片描述

不过由于上述的版本存在很多重复的计算,比如计算f(n)是会计算f(n-1)与f(n-2),而计算f(n-1)时则又会重新计算f(n-2),以此类推当n很大时,上面程序的复杂度会以指数级增长,因此这里就可以利用简单的动态规划思路来加速计算过程(有时候追本溯源还是很有用的,我们只需要像创始人那样创建一个表即可)。

#include <iostream>
#include <unordered_map>//创建一个表用于记录
std::unordered_map<int, int> fm;int f(int n)
{if (fm.find(n) != fm.end())return fm[n];if (n < 2){fm[n] = 1;return 1;}else{fm[n] = f(n - 1) + f(n - 2);return fm[n];}
}int main(int argc, char* argv[])
{// -------------------------动态规划---------------------------// 斐波那契数列int n = 7;		//以0为起始std::cout << "计算结果:" << f(n) << std::endl;std::cout << "计算结束!" << std::endl;return 0;
}

在这里插入图片描述

不过上述的代码仍然不够完美,这是因为我们是自顶向下的过程,这个过程中我们依赖于递归这种方式,存在许多函数调用的过程,因此我们可以继续简化:

#include <iostream>
#include <unordered_map>int main(int argc, char* argv[])
{// -------------------------动态规划---------------------------// 斐波那契数列int n = 7;		//以0为起始std::unordered_map<int, int> f;for (int i = 0; i <= n; ++i){if (i < 2)f[i] = 1;elsef[i] = f[i - 1] + f[i - 2];}std::cout << "计算结果:" << f[n] << std::endl;std::cout << "计算结束!" << std::endl;return 0;
}

在这里插入图片描述

2.2最短路径(DFS)

假设从一个棋盘的左上角走到右下角,求取最大路径之和,思路其实和上面相同,只是操作上略有不同:

// 标准文件
#include <iostream>
#include <thread>
#include <chrono>
#include <vector>
#include <fstream>
#include <stack>#define COMP >static int maxPathSum(std::vector<std::vector<int>>& grid) {int b = grid[0].size();int c = grid.size();std::vector<std::vector<float>> dp(c);std::vector<std::vector<std::pair<int, int>>> coords(c);for (int i = 0; i < dp.size(); ++i){dp[i].resize(b);coords[i].resize(b);}//int dp[c][b];std::cout << "行数:" << c << ",列数:" << b << std::endl;dp[0][0] = grid[0][0];coords[0][0] = std::make_pair(-1, -1);//初始化行for (int i = 1; i < c; i++){dp[i][0] = dp[i - 1][0] + grid[i][0];coords[i][0] = std::make_pair(i - 1, 0);}//初始化列for (int j = 1; j < b; j++){dp[0][j] = dp[0][j - 1] + grid[0][j];coords[0][j] = std::make_pair(0, j - 1);}for (int i = 1; i < c; i++){for (int j = 1; j < b; j++){if (dp[i - 1][j] COMP dp[i][j - 1]&& dp[i - 1][j] COMP dp[i - 1][j - 1]){coords[i][j] = std::make_pair(i - 1, j);dp[i][j] = dp[i - 1][j] + grid[i][j];}else if (dp[i - 1][j - 1] COMP dp[i][j - 1]&& dp[i - 1][j - 1] COMP dp[i - 1][j]){coords[i][j] = std::make_pair(i - 1, j - 1);dp[i][j] = dp[i - 1][j - 1] + grid[i][j];}else{coords[i][j] = std::make_pair(i, j - 1);dp[i][j] = dp[i][j - 1] + grid[i][j];}//dp[i][j] = std::max(dp[i - 1][j],//    std::max(dp[i - 1][j - 1], dp[i][j - 1]))//    + grid[i][j];}}//距离矩阵std::cout << "距离矩阵:" << std::endl;for (int i = 0; i < dp.size(); ++i){std::vector<float> row = dp[i];for (int j = 0; j < row.size(); ++j){std::cout << row[j] << " ";}std::cout << std::endl;}//索引矩阵std::cout << "索引矩阵:" << std::endl;for (int i = 0; i < coords.size(); ++i){std::vector<std::pair<int, int>> row = coords[i];for (int j = 0; j < row.size(); ++j){std::cout << "(" << row[j].first << "," << row[j].second << ")" << " ";}std::cout << std::endl;}std::cout << "输出路径:" << std::endl;std::deque<std::pair<int, int>> queue;queue.push_front(std::make_pair(c - 1, b - 1));std::pair<int, int> pos = coords[c - 1][b - 1];while (pos.first > -1){queue.push_front(pos);pos = coords[pos.first][pos.second];}for (int i = 0; i < queue.size() - 1; ++i){std::cout << "(" << queue[i].first << "," << queue[i].second << ")" << "->";}std::cout << "(" << queue[queue.size() - 1].first << ","<< queue[queue.size() - 1].second << ")" << "\n";return dp[grid.size() - 1][grid[0].size() - 1];
}int main(int argc, char** argv)
{// ---------------------输入数据---------------------std::vector<std::vector<int>> data ={{1,3,1,1},{1,5,1,1},{4,2,1,1}};// ---------------------动态规划---------------------std::cout << "最大距离:" << maxPathSum(data) << std::endl;return 0;
}

在这里插入图片描述

参考资料

[1]https://leetcode.com/problems/minimum-path-sum/description/
[2]https://www.youtube.com/watch?v=OQ5jsbhAv_M

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【JavaEE初阶系列】——多线程案例一——单例模式 (“饿汉模式“和“懒汉模式“以及解决线程安全问题)

目录 &#x1f6a9;单例模式 &#x1f388;饿汉模式 &#x1f388;懒汉模式 ❗线程安全问题 &#x1f4dd;加锁 &#x1f4dd;执行效率提高 &#x1f4dd;指令重排序 &#x1f36d;总结 单例模式&#xff0c;非常经典的设计模式&#xff0c;也是一个重要的学科&#x…

摆扫式(whisk broom)和推扫式(push broom)卫星传感器介绍

目前&#xff0c;我们卫星传感器主要有两大类型&#xff1a;摆扫式&#xff08;whisk broom&#xff09;和推扫式&#xff08;push broom&#xff09;。为了更好的理解和使用卫星影像数据&#xff0c;我们需要简单了解下这两种传感器工作原理。 摆扫式&#xff1a;Whisk Broom…

搭建Hadoop HA

目录 前言 搭建前准备 搭建 前言 Hadoop是一个由Apache基金会所开发的分布式系统基础架构&#xff0c;它允许用户在不了解分布式底层细节的情况下开发分布式程序&#xff0c;充分利用集群的威力进行高速运算和存储。Hadoop主要解决大数据存储和大数据分析两大核心问题&…

Phoenix概念篇

文章目录 前言Phoenix的web层概念PlugEndpointRouterScopePipeline ControllerAction Component 一次请求 前言 Elixir和Phoenix的作者也是Rails社区的核心开发者&#xff0c;如果是之前接触过Ruby on Rails的开发者&#xff0c;对Phoenix也许不会感到太陌生。笔者没有接触过R…

【报错】使用gradio渲染html页面无法加载本地图片

【报错】使用gradio渲染html页面无法加载本地图片 【报错】使用gradio渲染html页面无法加载本地图片[HTML] how to load local image by html output #884成功解决 【报错】使用gradio渲染html页面无法加载本地图片 在使用gradio框架渲染html页面&#xff0c;使用绝对路径&quo…

BUUCTF-Misc14

[WUSTCTF2020]find_me1 1.打开附件 是一个学校的校徽 2.盲文解密 发现图片属性里的备注是一串盲文 用在线盲文解密 3.得到flag

C语言笔记:重学输入和输出

ACM金牌带你零基础直达C语言精通-课程资料 本笔记属于船说系列课程之一&#xff0c;课程链接&#xff1a;ACM金牌带你零基础直达C语言精通https://www.bilibili.com/cheese/play/ep159068?csourceprivate_space_class_null&spm_id_from333.999.0.0 你也可以选择购买『船说…

AI新工具 视频迁移升级中国水墨画风格2.0;新颖的视频编辑框架提示编辑,风格转移,身份操控都不在话下;提取多种风格人脸草图

✨ 1: DomoAI 升级中国水墨画风格2.0 DomoAI是一个多功能的AI视频处理工具&#xff0c;可以将视频转换成多种风格&#xff0c;包括日本动漫、3D卡通、漫画和像素风格等。用户只需上传原始视频&#xff0c;通过简单的操作就能实现风格转换&#xff0c;制作出具有个性的高质量视…

“架构(Architecture)” 一词的定义演变历史(依据国际标准)

深入理解“架构”的客观含义&#xff0c;不仅能使IT行业的系统架构设计师提升思想境界&#xff0c;对每一个积极的社会行动者而言&#xff0c;也具有长远的现实意义&#xff0c;因为&#xff0c;“架构”一词&#xff0c;不只限于IT系统&#xff0c;而是指各类系统(包括社会系统…

蓝鹏智能测量仪应用于这些方面!助力发展新质生产力!

新质生产力是未来几年着重发展的方向&#xff0c;关于如何实现产业化升级&#xff0c;各厂家会在自身的基础上进行产业化调整升级&#xff0c;利用新工具、新手段&#xff0c;大幅缩短研发设计周期&#xff0c;从而让产品迭代速度不断加快&#xff1b;提升产品品质&#xff0c;…

堆排序(六大排序)

前面博客已经分享过堆的知识了&#xff0c;今天我们来分享堆排序。 堆排序 堆排序(Heapsort)是指利用堆积树&#xff08;堆&#xff09;这种数据结构所设计的一种排序算法&#xff0c;它是选择排序的一种。它是通过堆来进行选择数据。 ★★★需要注意的是排升序要建大堆&#…

3、创建项目,什么是路由

一、创建项目 第一次全局安装脚手架 npm install -g vue/clivue create 项目名 二、什么是路由&#xff1f; 路由就是一组 key-value 的对应关系多个路由&#xff0c;需要经过路由器的管理 1、后端路由&#xff1a; 每个url地址都对应着不同的静态资源对于普通的网站。所有…

24计算机考研调剂 | 【官方】湘潭大学

湘潭大学 考研调剂要求 招生专业&#xff1a; 调剂基本要求&#xff1a; &#xff08;1&#xff09;基本要求同《湘潭大学2024年硕士研究生复试录取工作方案》。 &#xff08;2&#xff09;初试成绩要求&#xff1a; 初试成绩各单科均须达到A类考生进入复试的初试成绩基本要…

007 日期类型相关工具类

推荐一篇文章 http://t.csdnimg.cn/72F7Jhttp://t.csdnimg.cn/72F7J

golang+vue微服务电商系统

golangvue微服务电商系统 文章目录 golangvue微服务电商系统一、项目前置准备二、项目简介三、代码GItee地址 golang、vue redis、mysql、gin、nacos、es、kibana、jwt 一、项目前置准备 环境的搭建 官方go开发工程师参考地址&#xff1a;https://blog.csdn.net/qq23001186/cat…

刷题记录:最长公共前缀

编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀&#xff0c;返回空字符串 ""。 示例 1&#xff1a; 输入&#xff1a;strs ["flower","flow","flight"] 输出&#xff1a;"fl"示例 2&#xff1a; 输…

【保姆级讲解Edge兼容性问题解决方法】

&#x1f308;个人主页:程序员不想敲代码啊&#x1f308; &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家&#x1f3c6; &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d; 希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提…

java算法第32天 | 贪心算法 part02 ● 122.买卖股票的最佳时机II ● 55. 跳跃游戏 ● 45.跳跃游戏II

122.买卖股票的最佳时机II 本题中理解利润拆分是关键点&#xff01; 不要整块的去看&#xff0c;而是把整体利润拆为每天的利润。假如第 0 天买入&#xff0c;第 3 天卖出&#xff0c;那么利润为&#xff1a;prices[3] - prices[0]。 相当于(prices[3] - prices[2]) (prices[…

从IO操作与多线程的思考到Redis-6.0

IO操作->线程阻塞->释放CPU资源->多线程技术提升CPU利用率 在没有涉及磁盘操作和网络请求的程序中&#xff0c;通常不会出现线程等待状态。线程等待状态通常是由于线程需要等待某些事件的发生&#xff0c;比如I/O操作完成、网络请求返回等。如果程序只是进行计算或者简…

常见端口及对应服务

6379 redis未授权 7001、7002 weblogic默认弱口令、反序列化 9200、9300 elasticsearch 参考乌云&#xff1a;多玩某服务器ElasticSearch命令执行漏洞 11211 memcache未授权访问 50000 SAP命令执行 50070、50030 hadoop默认端口未授权访问