广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >c++动态规划经典算法
  • 933
分享到

c++动态规划经典算法

2024-04-02 19:04:59 933人浏览 独家记忆
摘要

目录基本思想重要分析问题方法动态规划算法实例1、台阶问题2、从矩阵左上角走到右下角最短路径问题3、最大子数组问题4、最长公共子序列基本思想    &nb

基本思想

         动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中,可能会有许多可行解。每一个解都对应于一个值,我们希望找到具有最优值的解。动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。与分治法不同的是,适合于用动态规划求解的问题,经分解得到子问题往往不是互相独立的。若用分治法来解这类问题,则分解得到的子问题数目太多,有些子问题被重复计算了很多次。如果我们能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,节省时间。我们可以用一个表来记录所有已解的子问题的答案。不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表中。这就是动态规划法的基本思路。具体的动态规划算法多种多样,但它们具有相同的填表格式。

重要分析问题方法

        动态规划算法跟数组有着密切的关系,因此推荐大家在分析动态规划的算法时画一张表格(建议使用excel)分析解决问题往往能够事半功倍。

动态规划算法实例

1、台阶问题

 问题描述:有10级台阶,一个人每次上一级或者两级,问有多少种走完10级台阶的方法。

结合表格分析问题,每个子问题都只跟台阶这个变量相关,可以画出一个一维表格进行分析。

  1 2 3 4 5 6 7 8 9 10
走法 1 2 3 5 8 13 21 34 55 89

分析边界条件:对于每个台阶每次上一级或者两级,当台阶数为1时走法为1(即走一级即毕)为2时走法为2(走两次一级和走一次二级)。

分析递归关系:对于任一台阶都可以分为通过两级或者一阶到达。

      

终于,在有了上述两个条件之后,问题轻易得到了求解。(结合表格分析的手段到这里还没有完全发挥出它该有的优势,大家拭目以待)

台阶问题基于c++的代码实现:


// ConsoleApplication2.cpp : 定义控制台应用程序的入口点。
//
//台阶问题:有一座高度是10级台阶的楼梯,从下往上走,每跨一步只能向上1级或者2级台阶。要求用程序来求出一共有多少种走法。
#include "stdafx.h"
#include <iOStream>
using namespace std;
int getResultByDP(int n)//自底向上的问题解法
{
	if (n<1)
	{
		return 0;
	}
	if (n==1)
	{
		return 1;
	}
	if (n==2)
	{
		return 2;
	}
	int a = 1;//从两个递归基开始
	int b = 2;
	int temp = 0;
	for (int i = 3; i < n + 1; i++)
	{
		temp = a + b;
		a = b;
		b = temp;
	}
	return temp;
}
int _tmain(int arGC, _TCHAR* argv[])
{
	cout << getResultByDP(10);
	system("pause");
	return 0;
}

2、从矩阵左上角走到右下角最短路径问题

问题描述:给定一个矩阵m,从左上角开始每次只能向右走或者向下走,最后达到右下角的位置,路径中所有数字累加起来就是路径和,返回所有路径的最小路径和,如果给定的m如下,那么路径1,3,1,0,6,1,0就是最小路径和,返回12.

1 3 5 9

8 1 3 4

5 0 6 1

8 8 4 0

矩阵从左上角走到右下角
  0 1 2 3 4
0 0 0 0 0 0
1 0 1 3 5 9
2 0 8 1 3 5
3 0 5 0 6 1
4 0 8 8 4 0
           
  0 1 2 3 4
0 0 0 0 0 0
1 0 1 4 9 18
2 0 9 5 8 13
3 0 14 5 11 12
4 0 22 13 15 12

边界条件分析:由问题知道对于任一矩阵中的元素而言,上次位置或者是在该元素的坐标或者上边。那么当一些元素没有左边或者上边时应该怎么做呢?不妨就说的更为具体一些吧,如上图的表格所示当x(表示行下标)等于1,和y(表示列下标)等于1时正好是对应没有上边元素和没有左边元素的情况。对于只有左边元素的值array[x][y]=array[x][y-1]+m[x][y],对于只有上边元素:array[x][y]=array[x-1][y]+m[x][y](array为下面统计问题结果的二维数组,m为包含输入矩阵信息的二维数组)。

递归公式:对于平凡的子问题而言 (推导递归公式时刻意的考察array[x][y]和array[x-1][y]与array[x][y-1]的实际关系)

对于此问题而言:arry[x][y]=min(array[x-1][y],array[x][y-1])+m[x][y]

以下是该问题基于c++的代码实现:


//给定一个矩阵m,从左上角开始每次只能向右走或者向下走,最后达到右下角的位置,路径中所有数字累加起来就是路径和,返回所有路径的最小路径和,如果给定的m如下,那么路径1,3,1,0,6,1,0就是最小路径和,返回12.
#include "stdafx.h"
#include <string>
#include <iostream>
#include <alGorithm>
using namespace std;
int const x_length=5, y_length=5;
int m[x_length][y_length] = {
	0, 0, 0, 0, 0,
	0, 1, 3, 5, 9,
	0, 8, 1, 3, 5,
	0, 5, 0, 6, 1,
	0, 8, 8, 4, 0
};
int minDis() //m二级指针(可以是一个二维数组)
{
	int dp[4 + 1][4 + 1];
	//---------初始化边界条件-----------------
	for (size_t i = 0; i < x_length; i++)
	{
		dp[i][0] = 0;
	}
	for (size_t j = 0; j < y_length; j++)
	{
		dp[0][j] = 0;
	}
	//-------------------------------------------
	for (size_t i = 1; i < x_length; i++)
	{
		for (size_t j= 1; j < y_length; j++)
		{
			if (i == 1)
			{
				dp[i][j] = dp[i][j - 1] + m[i][j];
			}
			else if (j == 1)
			{
				dp[i][j] = dp[i - 1][j] + m[i][j];
			}
			else
			{
				int temp1 = dp[i - 1][j] + m[i][j];
				int temp2 = dp[i][j - 1] + m[i][j];
				dp[i][j] = min(temp1, temp2);
			}			
		}
	}
	return dp[x_length - 1][y_length - 1];
}
int _tmain(int argc, _TCHAR* argv[])
{
	cout << "最右下角的最短路径为:" << minDis();
	system("pause");
	return 0;
}

3、最大子数组问题

问题描述:给定数组arr,返回arr的最长递增子序列的长度,比如arr=[2,1,5,3,6,4,8,9,7],最长递增子序列为[1,3,4,8,9]返回其长度为5,由于该问题中总要把当前元素和在他之前的进行分析,我们也是借助表格来直观的分析该问题。

    2 4 5 3 1    
    0 1 2 3 4 5 6
2 0              
4 1              
5 2              
3 3              
1 4              
                 
0 1 2 3 4        
1 2 3 2 1        

边界条件:显然对于第一个数而言有dp[0]=1(dp表示存放结果的数组)

递归公式:首先生成dp[n]的数组,dp[i]表示以必须arr[i]这个数结束的情况下产生的最大递增子序列的长度。对于第一个数来说,很明显dp[0]为1,当我们计算dp[i]的时候,我们去考察i位置之前的所有位置,找到i位置之前的最大的dp值,记为dp[j](0=<j<i),dp[j]代表以arr[j]结尾的最长递增序列,而dp[j]又是之前计算过的最大的那个值,我们在来判断arr[i]是否大于arr[j],如果大于dp[i]=dp[j]+1.计算完dp之后,我们找出dp中的最大值,即为这个串的最长递增序列。

该问题基于c++的代码实现:


//给定数组arr,返回arr的最长递增子序列的长度,比如arr=[2,1,5,3,6,4,8,9,7],最长递增子序列为[1,3,4,8,9]返回其长度为5.
#include "stdafx.h"
#include <string>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int dp[5] = {};
int _tmain(int argc, _TCHAR* argv[])
{
 int arr[5] = { 2, 4, 5, 3, 1 };
 dp[0] = 1;
 const int oo = 0;
 for (int i = 1; i<5; i++){
  int _max = oo;
  for (int j = 0; j<i; j++)
   if (dp[j]>_max && arr[i]>arr[j])
    _max = dp[j];
  dp[i] = _max + 1;
 }
 int maxlist = 0;
 for (int i = 0; i < 5; i++)
  if (dp[i] > maxlist)
   maxlist = dp[i];
 cout << maxlist << endl;
 system("pause");
 return 0;
}

4、最长公共子序列

问题描述:给定两个字符串str1和str2,返回两个字符串的最长公共子序列,例如:str1="1A2C3D4B56",str2="B1D23CA45B6A","123456"和"12C4B6"都是最长公共子序列,返回哪一个都行。

问题分析:首先生成dp[n]的数组,dp[i]表示以必须arr[i]这个数结束的情况下产生的最大递增子序列的长度。对于第一个数来说,很明显dp[0]为1,当我们计算dp[i]的时候,我们去考察i位置之前的所有位置,找到i位置之前的最大的dp值,记为dp[j](0=<j<i),dp[j]代表以arr[j]结尾的最长递增序列,而dp[j]又是之前计算过的最大的那个值,我们在来判断arr[i]是否大于arr[j],如果大于dp[i]=dp[j]+1.计算完dp之后,我们找出dp中的最大值,即为这个串的最长递增序列。

    B D C A B A  
    0 1 2 3 4 5  
A 0 0 0 0 0 0 0 0
B 1 0 0 0 0 1 1 1
C 2 0 1 1 1 1 2 2
B 3 0 1 1 2 2 2 2
D 4 0 1 1 2 2 3 3
A 5 0 1 2 2 2 3 3
B 6 0 1 2 2 3 3 4
  7 0 1 2 2 3 4 4
                 
    B D C A B A  
    0 1 2 3 4 5  
A 0 -2 -2 -2 -2 -2 -2 -2
B 1 -2 -1 -1 -1 0 1 0
C 2 -2 0 1 1 -1 0 1
B 3 -2 -1 -1 0 1 -1 -1
D 4 -2 0 -1 -1 -1 0 1
A 5 -2 -1 0 -1 -1 -1 -1
B 6 -2 -1 -1 -1 0 -1 0
  7 -2 0 -1 -1 -1 0 -1

该问题基于c++代码实现:


//输入为两个长度不为零的字符串,输出这两个字符串的最大公共子序列
#include "stdafx.h"
#include <string>
#include <iostream>
#ifndef MAX
#define MAX(X,Y) ((X>=Y)? X:Y)
#endif
using namespace std;
int **Lcs_length(string X, string Y, int **B)
{
 int x_len = X.length();
 int y_len = Y.length();
 int **C = new int *[x_len + 1];
 for (int i = 0; i <= x_len; i++)
 {
  C[i] = new int[y_len + 1];        //定义一个存放最优解的值的表;
 }
 for (int i = 0; i <= x_len; i++)
 {
  C[i][0] = 0;
  B[i][0] = -2;                     //-2表示没有方向
 }
 for (int j = 0; j <= y_len; j++)
 {
  C[0][j] = 0;
  B[0][j] = -2;
 }
 for (int i = 1; i <= x_len; i++)
 {
  for (int j = 1; j <= y_len; j++)
  {
 
   if (X[i - 1] == Y[j - 1])
   {
    C[i][j] = C[i - 1][j - 1] + 1;
 
    B[i][j] = 0;             //0表示斜向左上
   }
   else
   {
    if (C[i - 1][j] >= C[i][j - 1])
    {
     C[i][j] = C[i - 1][j];
     B[i][j] = -1;       //-1表示竖直向上;
    }
    else
    {
     C[i][j] = C[i][j - 1];
     B[i][j] = 1;        //1表示横向左
    }
   }
 
  }
 }
 return C;
}
 
void OutPutLCS(int **B, string X, int str1_len, int str2_len)
{
 if (str1_len == 0 || str2_len == 0)
 {
  return;
 }
 if (B[str1_len][str2_len] == 0)   //箭头斜向左上
 {
  OutPutLCS(B, X, str1_len - 1, str2_len - 1);
  cout << X[str1_len - 1] << endl;
 }
 else if (B[str1_len][str2_len] == -1)
 {
  OutPutLCS(B, X, str1_len - 1, str2_len);
 }
 else
 {
  OutPutLCS(B, X, str1_len, str2_len - 1);
 }
}
 
int _tmain(int argc, _TCHAR* argv[])
{
 string X = "ABCBDAB";
 string Y = "BDCABA";
 
 int x_len = X.length();
 int y_len = Y.length();
 
 int **C;//定义一个二维数组
 
 int **B = new int *[x_len + 1];
 for (int i = 0; i <= x_len; i++)
 {
  B[i] = new int[y_len + 1];
 }
 C = Lcs_length(X, Y, B);
 for (int i = 0; i <= x_len; i++)
 {
  for (int j = 0; j <= y_len; j++)
  {
   cout << C[i][j] << " ";
  }
  cout << endl;
 }
 cout << endl;
 for (int i = 0; i <= x_len; i++)
 {
  for (int j = 0; j <= y_len; j++)
  {
   cout << B[i][j] << " ";
  }
  cout << endl;
 }
 OutPutLCS(B, X, x_len, y_len);//构造最优解
 system("pause");
 return 0;
}

到此这篇关于c++动态规划经典算法的文章就介绍到这了,更多相关c++动态规划内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: c++动态规划经典算法

本文链接: https://www.lsjlt.com/news/132784.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • c++动态规划经典算法
    目录基本思想重要分析问题方法动态规划算法实例1、台阶问题2、从矩阵左上角走到右下角最短路径问题3、最大子数组问题4、最长公共子序列基本思想    &nb...
    99+
    2022-11-12
  • C++ 动态规划算法使用分析
    目录Fibonacci字符串分割(Word Break)三角矩阵(Triangle)路径总数(Unique Paths)最小路径和(Minimum Path Sum)Fibonacc...
    99+
    2022-11-13
  • C++动态规划算法如何使用
    这篇“C++动态规划算法如何使用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“C++动态规划算法如何使用”文章吧。Fibon...
    99+
    2023-06-29
  • c语言动态规划算法是什么
    C语言动态规划算法是一种用于解决优化问题的算法。它通过将问题划分为子问题,并保存子问题的解来避免重复计算,从而提高算法的效率。动态规...
    99+
    2023-08-18
    c语言
  • C++动态规划算法实现矩阵链乘法
    问题描述: 给定n个矩阵的链<A1,A2,…,An>,矩阵Ai的规模为p(i-1)×p(i) (1<=i<=n),求完全括号化方案,...
    99+
    2022-11-13
  • 60题学会动态规划系列:动态规划算法第三讲
    简单多状态问题 文章目录 一.按摩师二.打家劫舍系列三.删除并获得点数四.粉刷房子 1.按摩师 力扣链接:力扣 一个有名的按摩师会收到源源不断的预约请求,每个预约都可以选择接或不接。在每次预约服务之间要有休息时间,因...
    99+
    2023-10-05
    c++ 后端 算法 动态规划 力扣
  • python动态规划算法怎么用
    小编给大家分享一下python动态规划算法怎么用,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!python有哪些常用库python常用的库:1.requesuts;2.scrapy;3.pillow;4.twisted;5...
    99+
    2023-06-14
  • C++动态规划计算最大子数组
    目录例题1.求最大的子数组的和2.求和最大的相应子数组例题 题目:输入一个整形数组,数组里有正数也有负数。数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。求所有子数组...
    99+
    2022-11-13
  • 【路径规划】局部路径规划算法——DWA算法(动态窗口法)|(含python实现 | c++实现)
    文章目录 参考资料1. DWA算法原理1.1 简介1.2 算法原理1. 速度采样2. 轨迹预测(轨迹推算)3. 轨迹评价 2. Python实现2.1 参数配置2.2 机器人运动学模...
    99+
    2023-08-31
    python 机器人 路径规划 DWA 动态窗口法
  • 怎么使用C++动态规划算法实现矩阵链乘法
    这篇文章主要介绍“怎么使用C++动态规划算法实现矩阵链乘法”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“怎么使用C++动态规划算法实现矩阵链乘法”文章能帮助大家解决问题。问题描述:给定n个矩阵的链&...
    99+
    2023-07-02
  • C++编辑距离(动态规划)
    题目描述: 给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。 我们可以对一个单词进行如下三种操作: 插入一个字符删除一个...
    99+
    2022-11-12
  • Java多种经典排序算法(含动态图)
    算法分析 一个排序算法的好坏,一般是通过下面几个关键信息来分析的,下面先介绍一下这几个关键信息,然后再将常见的排序算法的这些关键信息统计出来。 名词介绍 时间复杂度:指对数...
    99+
    2022-11-12
  • java背包问题动态规划算法分析
    背包问题 【题目描述】 一个旅行者有一个最多能装 MM 公斤的背包,现在有 nn 件物品,它们的重量分别是W1,W2,…,WnW1,W2,…,Wn,它们的价值分别为C1,C2,…,C...
    99+
    2022-11-12
  • python实现动态规划算法的示例代码
    动态规划(Dynamic Programming,DP)是一种常用的算法思想,通常用于解决具有重叠子问题和最优子结构性质的问题。动态规划算法通常是将问题分解为子问题,先解决子问题,再...
    99+
    2023-02-16
    python 动态规划算法
  • 怎么使用C++动态规划计算最大子数组
    本文小编为大家详细介绍“怎么使用C++动态规划计算最大子数组”,内容详细,步骤清晰,细节处理妥当,希望这篇“怎么使用C++动态规划计算最大子数组”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。例题题目:输入一个整形...
    99+
    2023-07-02
  • C语言动态内存规划详解
    目录动态内存规划动态内存函数的介绍总结动态内存规划 用C语言写程序时,因为语言的一些特性使用数组的时候只能用常量来申明数组,就导致数组的内存被卡得很死,不能根据我们的实际需求灵活的使...
    99+
    2022-11-12
  • C++实现动态规划过程详解
    目录C++实现动态规划1. 动态规划的基础2. 动态规划的实现方法3. 实际应用C++实现动态规划 动态规划是解决一类最优问题的常用方法,它是解决最优化问题的一种途径,因为这种算法通...
    99+
    2023-05-20
    C++实现动态规划 C++动态规划
  • Java算法之BFS,DFS,动态规划和贪心算法的实现
    目录前言广度优先搜索深度优先搜索动态规划贪心总结前言 广度优先搜索(BFS)和深度优先搜索(DFS)是图遍历算法中最常见的两种算法,主要用于解决搜索和遍历问题。动态规划和贪心算法则用...
    99+
    2023-05-14
    Java BFS Java DFS Java动态规划 Java贪心
  • 轨迹规划 | 图解动态窗口算法DWA(附ROS C++/Python/Matlab仿真)
    目录 0 专栏介绍1 动态障碍建模2 DWA基本原理2.1 采样窗口2.2 评价函数 3 DWA算法流程4 仿真实现4.1 ROS C++实现4.2 Python实现4.3 Matlab实...
    99+
    2023-10-18
    算法 机器人 ROS 自动驾驶 人工智能 原力计划
  • C#实现递归算法经典实例
    目录一 、递归算法简介二 、Fibonacci数列和阶乘1、Fibonacci数列2、阶乘三 、汉诺塔问题四 、排列组合1、输出任意个数字母、数字的全排列2、将全排列结果保存到链表中...
    99+
    2022-11-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作