首页 > 编程语言 >算法总结--动态规划

算法总结--动态规划

时间:2023-03-22 20:13:26浏览次数:55  
标签:总结 10 题目 -- int 算法 DP dp 方格

声明(叠甲):鄙人水平有限,本文为作者的学习总结,仅供参考。


1.动态规划介绍

动态规划,英文:Dynamic Programming,简称DP,如果某一问题有很多重叠子问题,使用动态规划是最有效的。其中每一个状态一定是由上一个状态推导出来,这是DP的一个重要标志。


2.DP大法的使用

一般的来说,使用DP大法一般有以下几个重要的步骤

【1】 确定 DP 数组下标的含义
【2】 根据题意推导出递归公式(状态转移方程)
【3】 初始化 DP 数组,一般要进行边界处理,有时也会通过扩大数组的大小来避免边界的处理
【4】 遍历 DP 数组,并进行对应的更新


3.举些栗子

3.1 线性 DP —— 斐波那契数

题目如下:

题目描述

斐波那契数?(通常用?F(n) 表示)形成的序列称为 斐波那契数列 。该数列由?0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:

F(0) = 0,F(1)?= 1
F(n) = F(n - 1) + F(n - 2),其中 n > 1

给定?n ,请计算 F(n) 。

根据题目描述显然这个问题可以使用 DP 大法进行求解,且已给出了其状态转移方程 F(n) = F(n - 1) + F(n - 2),以及对应的边界F(0) = 0,F(1)?= 1,于是我们就能够顺利写出对应的代码

int fib(int n) 
{
    if(n == 0) return 0;
    if(n == 1) return 1;
    int dp_n = 0;
    int dp_n_1 = 1;
    int dp_n_2 = 0;
    for(int i = 0;i < n-1;i++)
    {
        dp_n = dp_n_1 + dp_n_2;
        dp_n_2 = dp_n_1;
        dp_n_1 = dp_n;
    } 
    return dp_n;
}

3.2 二维 DP —— 过河卒

题目描述

棋盘上 $A$ 点有一个过河卒,需要走到目标 $B$ 点。卒行走的规则:可以向下、或者向右。同时在棋盘上 $C$ 点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。

棋盘用坐标表示,A 点 (0, 0)、B 点 (n, m),同样马的位置坐标是需要给出的。

现在要求你计算出卒从 $A$ 点能够到达 $B$ 点的路径的条数,假设马的位置是固定不动的,并不是卒走一步马走一步。

该题可以说是不同路径问题的变种,根据题目描述,我们可以设卒到(x,y)处的方案有dp[x][y]种,又卒只能向下、或者向右,故可以推出其状态转移方程为dp[x][y]=dp[x-1][y]+dp[x][y-1],接着是边界与特殊点(马的控制点)的处理,具体可以看代码的实现:

#include <bits/stdc++.h> 

using namespace std;

int main()
{
	int m,n,x_m,y_m;
	cin >> n >> m >> x_m >> y_m;
	long long int dp[n+1][m+1];
	for(int i = 0;i <= n;i++)
	{
		for(int j = 0;j <= m;j++)
		{
			int d_m = (i-x_m)*(i-x_m) + (j-y_m)*(j-y_m);     // 卒到马距离的平方
			if(d_m == 5 || d_m == 0) dp[i][j] = 0;
			else if(i == 0 && j == 0) dp[i][j] = 1;          // 起点
			else if(i == 0 && j != 0) dp[i][j] = dp[i][j-1]; // 上边界
			else if(j == 0 && i != 0) dp[i][j] = dp[i-1][j]; // 左边界
			else dp[i][j] = dp[i-1][j] + dp[i][j-1];         // 正常情况 
		}
	}
	cout << dp[n][m] << endl;
	return 0;
} 

3.2 四维 DP —— 方格取数

题目描述

设有 $N \times N$ 的方格图 $(N \le 9)$,我们将其中的某些方格中填入正整数,而其他的方格中则放入数字 $0$。如下图所示(见样例):

A
 0  0  0  0  0  0  0  0
 0  0 13  0  0  6  0  0
 0  0  0  0  7  0  0  0
 0  0  0 14  0  0  0  0
 0 21  0  0  0  4  0  0
 0  0 15  0  0  0  0  0
 0 14  0  0  0  0  0  0
 0  0  0  0  0  0  0  0
                         B

某人从图的左上角的 $A$ 点出发,可以向下行走,也可以向右走,直到到达右下角的 $B$ 点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字 $0$)。
此人从 $A$ 点到 $B$ 点共走两次,试找出 $2$ 条这样的路径,使得取得的数之和为最大。

该题的难点在于有两条路线同时进行,但是思考清楚后还是很简单的,按照 DP 大法的步骤来

【1】 设两条路径分别到两点 (i,j)与(k,l)时的最大的数为 DP[i][j][k][l]
【2】 根据观察可以推得状态转移方程为 DP[i][j][k][l] = max(a,b), 其中 a,b 如下:
a = max(dp[i-1][j][k-1][l],dp[i-1][j][k][l-1])
b = max(dp[i][j-1][k-1][l],dp[i][j-1][k][l-1])
【3】 边界的处理,在此我们可以多申明出一个都为 0 的第 0 行与第 0 列


代码实现如下:

#include <bits/stdc++.h> 

using namespace std;

int main()
{
	int nums[10][10] = {0,};
	int dp[10][10][10][10] = {0,};
	int n = 0;
	cin >> n;
	while(1)
	{
		int x,y,a;
		cin >> x >> y >>a;
		if(x == 0 && y == 0 && a == 0) break;
		nums[x][y] = a;
	}
	for(int i = 1;i <= n;i++)
	{
		for(int j = 1;j <= n;j++)
		{
			for(int k = 1;k <= n;k++)
			{
				for(int l = 1;l <= n;l++)
				{
					int a = max(dp[i-1][j][k-1][l],dp[i-1][j][k][l-1]);
					int b = max(dp[i][j-1][k-1][l],dp[i][j-1][k][l-1]);
					dp[i][j][k][l] = max(a,b) + nums[i][j] + nums[k][l];
					if(i == k && j == l) dp[i][j][k][l] -= nums[i][j];
				}
			}
		}
	}
	cout << dp[n][n][n][n];
	return 0;
} 

4.参考

代码随想录
4维DP例题讲解

本文到此结束,希望对您有所帮助。

标签:总结,10,题目,--,int,算法,DP,dp,方格
From: https://www.cnblogs.com/luokeIT/p/17245274.html

相关文章

  • 性能测试概念
    软件项目中性能测试的概念:性能测试是指通过特定方式,对被测系统按照一定策略施加压力,获取系统响应时间、TPS(TransactionPerSecond)、吞吐量、资源利用率等性能指标,以期保证......
  • CAD 2023 设置布局原点
    "布局"对应命令中的"Paper"("P")(而非"Layout"),在其他界面处或称为"图纸"。布局中的元素:虚线框为'可打印区域'可调整,可与图纸页面重合(默认情况下)橘色框为'可打印区域'左......
  • Commons-Collections1反序列化
    JDK版本为jdk8u65commons-collections版本为3.2.1InvokerTransformerCC1的漏洞点在InvokerTransformer,InvokerTransformer下有一个transform方法:publicObjecttransf......
  • 实验2
    实验任务1#include<stdio.h>#include<stdlib.h>#include<time.h>#defineN5#defineR1586#defineR2701intmain(){intnumber;inti;......
  • sqli-labs-Less-1
    主要工具:hackbar,firefox、bpLess-1根据提示输入id(hackbar工具)输入1成功输入1'失败错误信息YouhaveanerrorinyourSQLsyntax;checkthemanualthat......
  • 3.22总结
    <%@pagelanguage="java"contentType="text/html;charset=UTF-8"pageEncoding="UTF-8"%><!DOCTYPEhtml><html><head><metacharset="UTF-8"><title>Inserttitleh......
  • 图片懒加载
    图片懒加载之前学习vue2的时候,我了解到图片懒加载,只是当时没花时间去解决,仅仅是使用了vant2提供的懒加载插件,现在想尝试使用JS实现。什么是懒加载?其实就是在页面渲染时,不......
  • React 的学习笔记一 (未完结)
    一、React是什么 React是一个声明式,高效且灵活的用于构建用户界面的JavaScript库。使用React可以将一些简短、独立的代码片段组合成复杂的UI界面,这些代码片段被......
  • Webpack基础学习(一) (未完结)
    一、Webpack介绍与基本使用1.1、Webpack是什么?Webpack是一个静态资源打包工具。它会以一个或多个文件作为打包的入口,将我们整个项目所有文件编译组合成一个或多个文件......
  • Vue3学习笔记 —— 状态管理、Vuex、Pinia (未完结)
    优秀文章分享:vue中使用vuex(超详细)-掘金(juejin.cn)一、状态管理1.1、什么是状态管理?理论上来说,每一个Vue组件实例都已经在“管理”它自己的响应式状态了。我们以......