五大常规算法:动态规划算法

动态规划也是一种分治思想,与分治法不同的是:分治法是把原问题分解为若干子问题,由上而下解决,求解子问题,合并子问题的解从而得到原问题的解。动态规划也是一种自顶向下把原问题分解为子问题,不同的是,然后自底向上,向求解最小子问题,把结果粗出在表格中,在求解大的子问题时,直接从表格中查询小的子问题的解,避免重复计算,从而提高效率。


例如有一道例题

每次可以上1阶台阶,也可以上2阶台阶,求走一个n级台阶共有多少种走法。

 


我们先用分治法实现。

假设要走5级台阶,按照分治法思想,最后一步走1阶,前4级有多少种走法;或者左后一步走2阶,前3级有多少种走法。

我们将求n级台阶共有多少种走法用f(n)表示,则f(n)=f(n-1)+f(n-2)

由上可得 f(5) = f(4) +f(3) 

对于边界情况 f(1)=1  f(2) = 2

#include<iostream>
using namespace std;

int WalkCout(int n) {
	if (n < 0) return 0;
	if (n == 1) return 1; //一级台阶,一种走法
	else if (n == 2) return 2; //二级台阶,两种走法
	else { //n 级台阶, n-1 个台阶走法 + n-2 个台阶的走法
			return WalkCout(n - 1) + WalkCout(n - 2);
	}
}
int main(void) {
	cout << "5级台阶共有:" << WalkCout(5) << "种走法" << endl;
	
	system("pause");
	return 0;
}

运行结果

当我们将台阶级数改为40,并且增加一个时间戳计算一下时间

#include<time.h>

time_t begin, end;
time(&begin);
cout << "5级台阶共有:" << WalkCout(40) << "种走法" << endl;
time(&end);
cout << "用时为:" << end - begin << endl;

运行结果

这种计算方法会有很多的重复计算

例如在进行迭代时 f(4) =f(3) +f(2) =f(2) +f(1) +f(2)    f(3) =f(2) +f(1) 。f(2) +f(1)在之后的每次计算中都会被重复计算一次


如果我们从下往上推

f(1) =1

f(2) =2

f(3) = f(1) + f(2) =3

f(4) = f(3)+f(2) =3+2=5

#include<iostream>
#include<time.h>
using namespace std;

int WalkCout(int n) {
	if (n < 0) return 0;
	if (n == 1) return 1; //一级台阶,一种走法
	else if (n == 2) return 2; //二级台阶,两种走法
	
	int* value = new int[n + 1];
	value[0] = 0;
	value[1] = 1;
	value[2] = 2;
	for (int i = 3; i <= n; i++)
		value[i] = value[i - 1] + value[i - 2];
	int ret = value[n];
	delete value;
	return ret;
}
int main(void) {
	time_t begin, end;
	time(&begin);
	cout << "5级台阶共有:" << WalkCout(40) << "种走法" << endl;
	time(&end);
	cout << "用时为:" << end - begin << endl;
	system("pause");
	return 0;
}

运行结果

什么时候要用动态规划?
        如果要求一个问题的最优解(通常是最大值或者最小值),而且该问题能够分解成若干个子  问题,并且小问题之间也存在重叠的子问题,则考虑采用动态规划。
怎么使用动态规划?
五步曲解决:
        1. 判题题意是否为找出一个问题的最优解
        2. 从上往下分析问题,大问题可以分解为子问题,子问题中还有更小的子问题
        3. 从下往上分析问题 ,找出这些问题之间的关联(状态转移方程)
        4. 讨论底层的边界问题
        5. 解决问题(通常使用数组进行迭代求出最优解)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值