浅析动态规划(Dynamic Programming,DP)

这篇具有很好参考价值的文章主要介绍了浅析动态规划(Dynamic Programming,DP)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

动态规划可以理解为递归,只不过递归是通过函数实现,动态规划通过循环实现!

一、前言

动态规划有多好用我就不过多介绍,写这篇文章的时候我也不是熟练掌握,只是单纯记录一下我的学习经历并分享一些我的心得体会,仅此而已。

推荐看一下这个视频,对你的理解应该会有所帮助。

二、基本思想

动态规划最核心的思想,就在于拆分子问题,记住过往,减少重复计算。

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

三、解题步骤

这或许会包含各种各样的例题,我想从中进行对比以达成熟练掌握的目的,持续更新。。。

大致步骤如下:

  • 穷举分析
  • 确定边界
  • 找规律,确定最优子结构
  • 状态转移方程

例题一(最长递增子序列)

浅析动态规划(Dynamic Programming,DP),算法,动态规划,算法

1、穷举分析

自顶向上的穷举

这里观察规律,显然是有关系的,我们还是遵循动态规划自底向上的原则,基于示例1的数据,从数组只有一个元素开始分析。

  • 当nums只有一个元素10时,最长递增子序列是[10],长度是1.
  • 当nums需要加入一个元素9时,最长递增子序列是[10]或者[9],长度是1。
  • 当nums再加入一个元素2时,最长递增子序列是[10]或者[9]或者[2],长度是1。
  • 当nums再加入一个元素5时,最长递增子序列是[2,5],长度是2。
  • 当nums再加入一个元素3时,最长递增子序列是[2,5]或者[2,3],长度是2。
  • 当nums再加入一个元素7时,,最长递增子序列是[2,5,7]或者[2,3,7],长度是3。
  • 当nums再加入一个元素101时,最长递增子序列是[2,5,7,101]或者[2,3,7,101],长度是4。
  • 当nums再加入一个元素18时,最长递增子序列是[2,5,7,101]或者[2,3,7,101]或者[2,5,7,18]或者[2,3,7,18],长度是4。
  • 当nums再加入一个元素7时,最长递增子序列是[2,5,7,101]或者[2,3,7,101]或者[2,5,7,18]或者[2,3,7,18],长度是4。

通过上面分析,我们可以发现一个规律

如果新加入一个元素nums[i], 最长递增子序列要么是以nums[i]结尾的递增子序列,要么就是nums[i-1]的最长递增子序列

 原问题数组nums[i]的最长递增子序列 = 子问题数组nums[i-1]的最长递增子序列/nums[i]结尾的最长递增子序列

所以原问题,我们转化成求出以数组nums每个元素结尾的最长子序列集合,再取最大值。

浅析动态规划(Dynamic Programming,DP),算法,动态规划,算法

2、确定边界

当nums数组只有一个元素时,最长递增子序列的长度dp(1)=1,当nums数组有两个元素时,dp[2] =2或者1, 因此边界就是dp[1]=1。

3、最优子结构

从穷举分析,我们可以得出,以下的最优结构:

dp[i] = max(dp[j]) + 1,存在j属于区间[0,i-1],并且num[i] > num[j]。

max(dp[j]) 就是最优子结构。

4、状态转移方程

dp[i] = Math.max(dp[i], dp[j] + 1);

 5、代码实现

class Solution {
    public int lengthOfLIS(int[] nums) {
        int n=nums.length;
        if(n==1) return 1;
        if(n==0) return 0;
        int[] dp=new int[n];
        int res=0;
        Arrays.fill(dp,1);
        for(int i=1;i<n;i++){
            for(int j=0;j<i;j++){
                if(nums[i]>nums[j])
                {
                dp[i]=Math.max(dp[i],dp[j]+1);
                }
                res=Math.max(res,dp[i]);
            }
        }
        return res;
    }
}

6、复杂度

时间复杂度O(n^2),空间复杂度O(n)

例题二(过河卒)

浅析动态规划(Dynamic Programming,DP),算法,动态规划,算法

1、分析

 卒只能向下和向右走,所以当前点等于上面的点加左边的点的可能数

2、确定边界

显然,dp[0][0] = 1

3、状态转移方程

if (d[i][j] != -1) {
	if (i) dp[i][j] += dp[i - 1][j];
	if (j) dp[i][j] += dp[i][j - 1];
}

4、AC代码

#include<bits/stdc++.h>

#define MAX 30

using namespace std;

int d[MAX][MAX] = { 0 };
long long dp[MAX][MAX] = { 0 };//开long long防止数值过大

//用于马的控制点赋值
const int dx[] = { 2,1,-1,-2,-2,-1,1,2 };
const int dy[] = { 1,2,2,1,-1,-2,-2,-1 };

int main() {
	int bx, by, mx, my;
	cin >> bx >> by >> mx >> my;
	/*for (int i = 1; i < bx; i++) {
		dp[i][0] = 1;
	}
	for (int i = 1; i < by; i++) {
		dp[0][i] = 1;
	}*/
	d[mx][my] = -1;
	for (int i = 0; i < 8; i++) {//马控制点赋值
		if (mx + dx[i] >= 0 && mx + dx[i] <= bx && my + dy[i] >= 0 && my + dy[i] <= by) {
			d[mx + dx[i]][my + dy[i]] = -1;
		}
	}
	dp[0][0] = 1;
	for (int i = 0; i <= bx; i++) {//卒只能向下和向右走,所以当前点等于上面的点加左边的点的可能数
		for (int j = 0; j <= by; j++) {
			if (d[i][j] != -1) {
				if (i) dp[i][j] += dp[i - 1][j];
				if (j) dp[i][j] += dp[i][j - 1];
			}
		}
	}
	//打印地图和dp
	/*for (int i = 0; i <= by; i++) {
		for (int j = 0; j <= bx; j++) {
			cout << d[i][j]<< " ";
			if (j == bx) {
				cout << endl;
			}
		}
	}
	cout << endl;
	for (int i = 0; i <= by; i++) {
		for (int j = 0; j <= bx; j++) {
			cout << dp[i][j] << " ";
			if (j == bx) {
				cout << endl;
			}
		}
	}*/
	cout << dp[bx][by] << endl;
	return 0;
}

例题三(摆花)

浅析动态规划(Dynamic Programming,DP),算法,动态规划,算法

1、分析

定义状态:f(i,j) 表示前 i 个数总和为 j 的方案数。

2、状态转移方程

f(i,j)=f(i−1,j−k) (k从0到a[i])

其中, k是枚举当前第 i 个数的取值。

3、复杂度

时间复杂度:O(nmai​),稳得一批。

空间复杂度:O(nm)

4、代码

#include<bits/stdc++.h>
using namespace std;
const int maxn = 105, mod = 1000007;
int n, m, a[maxn], f[maxn][maxn];
int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> a[i];
    f[0][0] = 1;
    for (int i = 1; i <= n; i++)
        for (int j = 0; j <= m; j++)
            for (int k = 0; k <= min(j, a[i]); k++)
                f[i][j] = (f[i][j] + f[i - 1][j - k]) % mod;
    cout << f[n][m] << endl;
    return 0;
}

例题四(李白打酒加强版)

浅析动态规划(Dynamic Programming,DP),算法,动态规划,算法浅析动态规划(Dynamic Programming,DP),算法,动态规划,算法

1、分析

设 f[i][j][k] 为当前走到第 i 个位置,看了 j 次花,有 k 斗酒的方案数。

题目中说了初始两斗酒,那么 f[0][0][2]=1。

重点是怎么前推后,依次循环 i,j,k,

如果 f[i][j][k] 不是 0,那么我们在第 i+1 个位置看花或者经过酒店。

看花:走到第 i+1 个位置,看了 j+1 次花,酒的数量变为 k−1。

酒馆:走到第 i+1 个位置,看了 j 次花,酒的数量变为 k×2。

2、状态转移方程

if (f[i][j][k] != 0)//这里也可以简写成 if(f[i][j][k])
{
	f[i + 1][j + 1][k - 1] += f[i][j][k];
	f[i + 1][j][k * 2] += f[i][j][k];
}

j 只需要循环到 m−1,不需要循环到 m,如果循环到了 m:

首先,再看花变成 m+1 已经对答案没有任何的贡献了。

其次,这样还会多算。如果不看花只能是没有酒,一直经过酒店,

但是题目要求最后一次只能经过花,所以不行。

还有一个问题:酒的斗数上限是什么?

显然不会超过 m,不然最后的酒就喝不完了,所以也循环到 m。文章来源地址https://www.toymoban.com/news/detail-859591.html

3、代码 

#include <iostream>
using namespace std;
int n, m;
int f[205][105][105];
int main() {
	cin >> n >> m;
	f[0][0][2] = 1;
	for (int i = 0; i < n + m; i ++)
		for (int j = 0; j < m; j ++)
			for (int k = 0; k <= m; k ++)
				if (f[i][j][k]) {
					if (k > 0) 
                        f[i + 1][j + 1][k - 1] 
                        = (f[i + 1][j + 1][k - 1] + f[i][j][k]) % 1000000007;
					if (k <= 50) 
                        f[i + 1][j][k * 2] 
                        = (f[i + 1][j][k * 2] + f[i][j][k]) % 1000000007;
				}
	cout << f[n + m][m][0];
	return 0;
}

到了这里,关于浅析动态规划(Dynamic Programming,DP)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ​Python—数据结构与算法​---动态规划—DP算法(Dynamic Programing)

    目录 我们一路奋战, 不是为了改变世界, 而是为了不让世界改变我们。 动态规划——DP算法(Dynamic Programing) 一、🏔斐波那契数列(递归VS动态规划) 1、🐒斐波那契数列——递归实现(python语言)——自顶向下 2、🐒斐波那契数列——动态规划实现(python语言)——自底

    2024年02月10日
    浏览(32)
  • 动态规划Dynamic Programming

     上篇文章我们简单入门了动态规划(一般都是简单的上楼梯,分析数据等问题)点我跳转,今天给大家带来的是路径问题,相对于上一篇在一维中摸爬滚打,这次就要上升到二维解决问题,但都用的是动态规划思想嘛,所以大差不差,且听我慢慢道来。 还是用一样的方法,

    2024年03月27日
    浏览(35)
  • 动态规划(Dynamic Programming)详解

    引言: 动态规划(Dynamic Programming,简称DP)是计算机科学与数学领域中的一个经典算法设计策略,用于解决具有重叠子问题和最优子结构特性的复杂问题。它通过将问题分解为更小的子问题来避免重复计算,从而提高效率。本文旨在详细介绍动态规划的基本概念、原理、实现

    2024年04月13日
    浏览(26)
  • 【数据结构】动态规划(Dynamic Programming)

    求解决策过程(decision process)最优化的数学方法。 将多阶段决策过程转化为一系列单阶段问题,利用各阶段之间的关系,逐个求解。 与分治法类似,将待求解问题 分解成若干个子问题 。 但是经分解得到的子问题往往 不是相互独立 的。 如果使用分治法求解问题,有些子问

    2024年02月03日
    浏览(35)
  • Dynamic-Programming(动态规划)最细解题思路+代码详解(1)

    案例二:二维数组的 DP 我做了几十道 DP 的算法题,可以说,80% 的题,都是要用二维数组的,所以下面的题主要以二维数组为主,当然有人可能会说,要用一维还是二维,我怎么知道?这个问题不大,接着往下看。 问题描述 一个机器人位于一个 m x n 网格的左上角 (起始点在

    2024年04月26日
    浏览(27)
  • Dynamic-Programming(动态规划)最细解题思路+代码详解,Android布局优化之include、merge、ViewStub的使用

    dp[0…m-1] [0] = 1; // 相当于最左面一列,机器人只能一直往下走 撸代码 三个步骤都写出来了,直接看代码 public static int uniquePaths(int m, int n) { if (m = 0 || n = 0) { return 0; } int[][] dp = new int[m][n]; // // 初始化 for(int i = 0; i m; i++){ dp[i][0] = 1; } for(int i = 0; i n; i++){ dp[0][i] = 1; } // 推导出 d

    2024年04月26日
    浏览(30)
  • DP算法:动态规划算法

    (1)确定初始状态 (2)确定转移矩阵,得到每个阶段的状态,由上一阶段推到出来 (3)确定边界条件。 蓝桥杯——印章(python实现) 使用dp记录状态,dp[i][j]表示买i张印章,凑齐j种印章的概率 i表示买的印章数,j表示凑齐的印章种数 情况一:如果ij,不可能凑齐印章,概

    2024年02月07日
    浏览(37)
  • ★动态规划(DP算法)详解

    什么是动态规划:动态规划_百度百科 内容太多了不作介绍,重点部分是无后效性,重叠子问题,最优子结构。 问S-P1和S-P2有多少种路径数,毫无疑问可以先从S开始深搜两次,S-P1和S-P2找出所有路径数,但是当这个图足够大,那就会超时。 动态规划旨在用 空间换时间 ,我们

    2024年02月04日
    浏览(38)
  • 动态规划(DP)(算法笔记)

    本文内容基于《算法笔记》和官方配套练题网站“晴问算法”,是我作为小白的学习记录,如有错误还请体谅,可以留下您的宝贵意见,不胜感激。 动态规划(Dynamic Programming,DP)是一种用来解决一类最优化问题的算法思想。简单来说,动态规划将一个复杂的问题分解成若干个子

    2024年02月05日
    浏览(32)
  • 算法——动态规划(DP)——递推

    动态规划常用于解决优化问题。 动态规划通常以自底向上或自顶向下的方式进行求解。 自底向上的动态规划从最简单的子问题开始,逐步解决更复杂的问题,直到达到原始问题。 自顶向下的动态规划则从原始问题出发,分解成子问题,并逐步求解这些子问题。 动态规划算法

    2024年01月20日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包