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.rhkb.cn/news/287050.html

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

相关文章

淘宝app商品数据API接口|item_get_app-获得淘宝app商品详情原数据

获得淘宝app商品详情原数据 API返回值说明 item_get_app-获得淘宝app商品详情原数据 公共参数​​​​​​ 名称类型必须描述keyString是调用key&#xff08;必须以GET方式拼接在URL中&#xff09;secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地…

优化选址问题 | 基于和声搜索算法求解基站选址问题含Matlab源码

目录 问题代码问题 和声搜索算法(Harmony Search, HS)是一种模拟音乐创作过程中乐师们凭借自己的记忆,通过反复调整各乐器的音调,直至达到最美和声状态为启发,通过反复调整解向量的各分量来寻求全局最优解的智能优化算法。 下面是一个基于和声搜索算法求解基站选址问题的…

全面剖析Java多线程编程,抢红包、抽奖实战案例

黑马Java进阶教程&#xff0c;全面剖析Java多线程编程&#xff0c;含抢红包、抽奖实战案例 1.什么是多线程&#xff1f; 2.并发与并行 CPU有这些&#xff0c;4,8,16,32,64 表示能同时进行的线程 3.多线程的第一种实现方式 package com.itheima.reggie;/*** Author lpc* Date …

现在的市场对 C++ 的需求大吗?

先说结论&#xff1a;需求还是很大&#xff0c;但是没有什么初级程序员能干的岗位。 游戏引擎&#xff0c;存储&#xff0c;推荐引擎&#xff0c;infra&#xff0c;各种各样的性能敏感场景。 在开始前我分享下我的经历&#xff0c;我刚入行时遇到一个好公司和师父&#xff0c;…

RocketMQ学习笔记:消息存储模型,持久化文件,过期文件删除

这是本人学习的总结&#xff0c;主要学习资料如下 马士兵教育rocketMq官方文档 目录 1、消息存储结构1.1、CommitLog详解1.1.1、CommitLog存储的优点 1.2、ConsumeQueue详解1.3、Index详解 2、持久化文件3、过期文件删除机制3.1、判断过期文件3.2、删除的时机 1、消息存储结构…

大学宠物医疗试题及答案,分享几个实用搜题和学习工具 #学习方法#笔记#知识分享

大学开学&#xff0c;就意味着又回到了被线性代数、大学物理等测验题折磨的状态了……网站无法手动输入题干公式&#xff0c;初高中用过的搜题软件又都搜不到&#xff0c;想找个答案解析仿佛在大海捞针&#xff01;不过不用怕&#xff0c;今天小林就把从大学攒到毕业工作都在使…

一个单生产-多消费模式下无锁方案(ygluu/卢益贵)

一个单生产-多消费模式下无锁方案 ygluu/卢益贵 关键词&#xff1a;生产者-消费者模型、无锁队列、golang、RWMutex 本文介绍一个“单生产(低频)-多消费”模式下的无锁哈希类方案&#xff0c;这个方案的性能优于golang的RWMutex&#xff0c;因为它永远不会因为“写”而导致与…

网络上常见的环路指的是什么

人类的创造力与破坏力同样强大"。 网路互通&#xff0c;同样也衍生出纷繁复杂的路由协议和各种因特网服务&#xff0c;以及"网络安全"这个庞大的领域。 这也是为什么说当今所有的网络通讯流量中&#xff0c;80%的资源都被浪费&#xff0c;只有20%被用以有效数…

数字功放VS模拟功放,选择适合你的音频解决方案

数字功放和模拟功放是音频系统中常用的两种功放技术&#xff0c;适用于不同的音频应用&#xff0c;都具有各自的优势和特点。本文将为您详细介绍数字功放和模拟功放的差异&#xff0c;并帮助您找到适合自己的音频解决方案。 1、数字功放是一种利用数字信号处理技术的功放。它将…

matplotlib查询当前系统所有字体

电脑里有这个字体但是不代表matplotlib里也有这个字体&#xff0c;所以解决matplotlib中的中文显示问题主要就是要找到它所内置支持的字体&#xff0c;那么我们首先查看一下它的内置字体&#xff0c;运行以下代码查看所支持的字体 # 查询当前系统所有字体 from matplotlib.fon…

Qt笔记 事件处理_鼠标事件

什么是事件&#xff1f; 点击鼠标左键&#xff0c;双击鼠标左键&#xff0c;鼠标来回移动&#xff0c;按下键盘按钮&#xff0c;这些都是事件。 那么事件的响应机制是什么样的呢&#xff1f; 首先main函数中有一个QApplication&#xff0c;其作用是创建一个应用程序对象&…

IPV6协议之DHCPV6

目录 背景&#xff1a; 一、DHCPV6概述 DHCPv6 Client&#xff1a; DHCPv6 Relay&#xff1a; DHCPv6 Server&#xff1a; 二、DHCPV6工作原理 DHCPV6无状态自动分配 三、DHCP基础配置 服务端 四、DHCPV6地址更新时间&#xff08;DHCPV4租期&#xff09; 五、DHCPV6…

Spring设计模式-实战篇之单例模式

实现案例&#xff0c;饿汉式 Double-Check机制 synchronized锁 /*** 以饿汉式为例* 使用Double-Check保证线程安全*/ public class Singleton {// 使用volatile保证多线程同一属性的可见性和指令重排序private static volatile Singleton instance;public static Singleton …

智能楼宇3D可视化解决方案

什么是智能楼宇? 智能楼宇是为提高楼宇的使用合理性与效率,配置合适的建筑环境系统与楼宇自动化系统、办公自动化与管理信息系统以及先进的通信系统,并通过结构化综合布线系统集成为智能化系统的大楼。 面临的问题 信息孤岛,无法统一管理 各个子系统独立工作、独立管理,…

海外媒体软文发稿:谷歌关键词优化细分人群成功案例,突破海外市场!

海外媒体软文发稿&#xff1a;谷歌关键词优化细分人群成功案例&#xff0c;突破海外市场&#xff01; 引言 在全球化的时代&#xff0c;海外市场对于企业的发展至关重要。而在海外市场中&#xff0c;互联网媒体的作用不可忽视。本篇教程将介绍如何通过谷歌关键词优化细分人群…

Python框架篇(7):FastApi-依赖项

有时选择太多也会让人陷入焦虑&#xff0c;比如突然有一段自由时间&#xff0c;却因为想做的事情太多&#xff0c;最后把时间都浪费在了摇摆不定上&#xff0c;静不下心做最重要的事&#xff0c;或者说根本不知道最重要的事情是什么。---------- 《认知觉醒:开启自我改变的原动…

YOLOv9有效改进专栏汇总|未来更新卷积、主干、检测头注意力机制、特征融合方式等创新![2024/3/23]

​ 专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;助力高效涨点&#xff01;&#xff01;&#xff01; 专栏介绍 YOLOv9作为最新的YOLO系列模型&#xff0c;对于做目标检测的同学是必不可少的。本专栏将针对2024年最新推出的YOLOv9检测模型&#xff0…

为何ChatGPT日耗电超50万度?

看新闻说&#xff0c;ChatGPT每天的耗电量是50万度&#xff0c;国内每个家庭日均的耗电量不到10度&#xff0c;ChatGPT耗电相当于国内5万个家庭用量。 网上流传&#xff0c;英伟达创始人黄仁勋说&#xff1a;“AI的尽头是光伏和储能”&#xff0c;大佬的眼光就是毒辣&#xff…

这班上的值不值

各位打工人&#xff0c;是不是每天上班遇到烦心事时&#xff0c;心里就想&#xff0c;这xx工作真是干不下去了。 后来在一个群里有朋友分享了一个excel&#xff0c;用来测算自己这个班上的值不值 就是这个 后来excel找不到了。 想了一下&#xff0c;这玩意做个小程序这不很简单…

【数字图像处理 】 灰度变换增强图像

文章目录 灰度变换增强图像对数变换指数(伽玛)变换直方图均衡化变换 灰度变换增强图像 对数变换 对数变换的作用是对图像的低灰度范围进行扩展&#xff0c;并对高灰度范围进行压缩&#xff0c;得到的结 果图像灰度分布更均匀&#xff0c;其通用表达式为&#xff1a; y c log…