动态规划入门

动态规划入门

写一点我对动态规划的理解和相关题解

首先,我们来看看斐波那契数列 1,1,2,3,5…每一项是前两项的和,这是一个逐渐递增的数组;我们都知道它的算式是F(n)=F(n-1)+F(n-2);

输出斐波那契数列的前二十项

#include<iostream>
using namespace std;
int fib(int k)
{
	if (k == 1)return 1;
	if (k == 2)return 1;
	else return fib(k - 1) + fib(k - 2);
}
int main()
{
	for (int i = 1; i <= 20; i++)
		cout << fib(i) << endl;
	return 0;
}

其实这里的第n项是由前两项(n-1项和n-2项)加和得到的,由此可知,第三项是由第一项和第二项得到的。这里也就是递归的结束点,我们需要一个初始值让递归返还数值,这里的初始值为斐波那契数列的第一二项,由此计算出前二十项。现在再来看下一题;

跳台阶问题

有N级的台阶,你一开始在底部,每次可以向上迈最多2级台阶(最少1级),问到达第N级台阶有多少种不同方式?

如果你想跳上第三级台阶,那么你必须跳上第一级台阶在跳上第三级,或者跳上第二级在跳上第三级,那么就有2种方式;
同理,跳上第四级台阶,你就需要跳上第三级或者直接从第二级跳上;那么跳上第四级台阶的方法就转换成了跳上第二级台阶和跳上第三级台阶方法的和;跳上第三级台阶的方法有多少呢?我们之前已经计算过了,是两种+第二级(1种)=3种;在这里插入图片描述
那么第n级台阶就等于第n-1级加第n-2级;F(n)=F(n-1)+F(n-2)这和斐波那契数列是一样的;显然,这个算式是我们解题的关键。我们称它为**“状态转移方程”**
状态转移就是dp的思想;如果想通了,你可以去做一做它的原题
(改编自洛谷台阶https://www.luogu.com.cn/problem/P1192

第三题我们将一维dp拓展到二维

方格上的路径
在这里插入图片描述在这里插入图片描述
对于这题我们知道最短路径的数量(M+N) * (M+N-1) * …(N+1)/M!但是如果用这个算式计算,会非常慢,那么就需要用到dp;这里我们选择初始化第0行和第0列,我们需要用数据填满这个表格,从第一行第一列开始,表格的每一个数字都有其左边和上边的数字得到,那么不难得出状态转移方程 dp[i][j] = dp[i - 1][j] + dp[i][j - 1]

在这里插入图片描述
代码

using namespace std;
long long dp[101][101];
int n, m;
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		cin >> n >> m;
		for (int i = 0; i <= n; i++)
			dp[i][0]=1;
		for (int i = 0; i <= m; i++)
			dp[0][i] = 1;
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= m; j++)
				dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
		cout << dp[n][m]<<endl;
	}
	return 0;
}

加点难度,我们在这个表格上加入一些限制

洛谷过河卒
https://www.luogu.com.cn/problem/P1002

在这里插入图片描述
很显然状态转移方程依旧为dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
这题在对于数据的初始化上挖了坑,由此可见,解决dp问题时,数据的初始化也是不能忽视的;如下图情况:
在这里插入图片描述
不能全部初始化为1;由于只能向下或者向右第一行第一列马能跳到的地方后面自然也是不能走到的,需要初始化为0;
这题需要使用long long,数据会很大;

代码

#include<iostream>
using namespace std;
long long dp[25][25];
bool book[25][25];
int n, m;
int hx, hy;
int dir[8][2] = { {2,-1},{2,1},{1,-2},{1,2},{-1,2},{-1,-2},{-2,-1},{-2,1} };
int main()
{
	cin >> n >> m;
	cin >> hx >> hy;
	for (int k = 0; k < 8; k++)
	{
		int hxx = hx + dir[k][0];
		int hyy = hy + dir[k][1];
		if (hxx >= 0 && hyy >= 0 && hxx <= n && hyy <= m)
			book[hxx][hyy] = 1;
	}
	book[hx][hy] = 1;
	for (int k = 0; k <= m; k++)
		if (!book[0][k])
			dp[0][k] = 1;
		else break;//之后的全部为0,不能少
	for (int k = 0; k <= n; k++)
		if (!book[k][0])
			dp[k][0] = 1;
		else break;//同上
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			if (!book[i][j])
				dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
	cout << dp[n][m];
	return 0;
}

之后我们来看一道经典dp问题
数字三角形,又被称为树塔,需要我们查找最大路径,由于是查找最大的路径,我们就需要选择大的值向下转移;
在这里插入图片描述在这里插入图片描述

值得注意的是这次的最大值并不在最后一个取得;

代码

#include<iostream>
using namespace std;
int map[1001][1001];
int dp[1001][1001];
int maxx = -1;
int main()
{
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++)
		for(int j=1;j<=i;j++)
		  cin >> map[i][j];
	dp[1][1] = map[1][1];
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= i; j++)
		{
			dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - 1]) + map[i][j];
			if (dp[i][j] >= maxx)maxx = dp[i][j];
		}
	cout << maxx;
	return 0;
}	

这些都是一些动态规划相对入门的基础题,深入学习动态规划还有很长一段路要走,希望能够帮助你。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值