动态规划总结

动态规划算法详解及走方格问题

动态规划算法:
基本概念:
动态规划是运筹学中用于求解决策过程中的最优化数学方法。当然,我们在这里关注的是作为一种算法设计技术,作为一种使用多阶段决策过程最优的通用方法

基本思想:
基本思想与分治法类似,也是将待求解的问题分解为若干个子问题(阶段),按顺序求解子阶段,前一子问题的解,为后一子问题的求解提供了实用的信息。
在求解任一子问题时,列出各种可能的局部解,通过决策保留那些有可能达到最优的局部解,丢弃其它局部解。依次解决各子问题,最后一个子问题就是初始问题的解。
因为动态规划解决的问题多数有重叠子问题这个特点。为降低反复计算。对每个子问题仅仅解一次,将其不同阶段的不同状态保存在一个二维数组中。
与分治法最大的区别是:适合于用动态规划法求解的问题,经分解后得到的子问题往往不是互相独立的(即下一个子阶段的求解是建立在上一个子阶段的解的基础上,进行进一步的求解)。

动规解题的一般思路:

将原问题分解为子问题
把原问题分解为若干个子问题,子问题和原问题形式相同或类似,只不过规模变小了。子问题都解决,原问题即解决(以走方格问题为例)。
子问题的解一旦求出就会被保存,所以每个子问题只需求 解一次。

确定状态
在用动态规划解题时,我们往往将和子问题相关的各个变量的一组取值,称之为一个“状 态”。一个“状态”对应于一个或多个子问题, 所谓某个“状态”下的“值”,就是这个“状 态”所对应的子问题的解。
所有“状态”的集合,构成问题的“状态空间”。“状态空间”的大小,与用动态规划解决问题的时间复杂度直接相关。 在走方格的例子里,一共有N×N数字,所以这个问题的状态空间里一共就有N×N个状态。

确定一些初始状态(边界状态)的值
以“方格”为例,边界状态就是第一行与第一列,值就是1。

确定状态转移方程

定义出什么是“状态”,以及在该“状态”下的“值”后,就要找出不同的状态之间如何迁移――即如何从一个或多个“值”已知的 “状态”,求出另一个“状态”的“值”(递推型)。状态的迁移可以用递推公式表示,此递推公式也可被称作“状态转移方程”。

能用动规解决的问题的特点:

问题具有最优子结构性质。如果问题的最优解所包含的 子问题的解也是最优的,我们就称该问题具有最优子结 构性质。

无后效性。当前的若干个状态值一旦确定,则此后过程的演变就只和这若干个状态的值有关,和之前是采取哪种手段或经过哪条路径演变到当前的这若干个状态,没有关系。

有重叠子问题:即子问题之间是不独立的,一个子问题在下一阶段决策中可能被多次使用到(该性质并非动态规划适用的必要条件,可是假设没有这条性质。动态规划算法同其它算法相比就不具备优势)。

问题描述:

小王从目的地A要去目的地B,请问有多少种不同的路线?规则是只能向下和向右走,不能逆着走。
能用动规解决的问题的特点:
问题具有最优子结构性质。如果问题的最优解所包含的 子问题的解也是最优的,我们就称该问题具有最优子结 构性质。
无后效性。当前的若干个状态值一旦确定,则此后过程的演变就只和这若干个状态的值有关,和之前是采取哪种手段或经过哪条路径演变到当前的这若干个状态,没有关系。
有重叠子问题:即子问题之间是不独立的,一个子问题在下一阶段决策中可能被多次使用到(该性质并非动态规划适用的必要条件,可是假设没有这条性质。动态规划算法同其它算法相比就不具备优势)。
在这里插入图片描述
假如B在A的下面,那么只有一种情况,B在A的右边也只有一种情况,然后依次将方格中的数据填上对应的数据大小,如图所示:
在这里插入图片描述
由上图能够清楚的得到,里面的数据类似于杨辉三角,因此类似可以借助杨辉三角的方式来进行计算A到B之间到底有多少种路线?
程序如下:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>

int main(){
	int a[10][10] = { 0 };
	int m, n;
	int i = 0, j = 0;
	printf("请输入表格的行与列:");
	scanf("%d%d", &m, &n);
	for (i = 1; i <= m; i++){
		for (j = 1; j <= n; j++){
			if (i == 1 && j == 1){
				a[i][j] = 1;
			}
			else{
				a[i][j] = a[i - 1][j] + a[i][j - 1];
			}
		}
	}
	printf("共有%d种不同的路线\n", a[m][n]);
	system("pause");
	return 0;
}

运行结果:
在这里插入图片描述
**拓展:**假如恰好A与B之间有一条河流不能通过,
在这里插入图片描述

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>

int main(){
	int a[10][10] = { 0 };
	int m = 0, n = 0;
	int M, N;
	int i = 0, j = 0;

	printf("请输入表格的行与列:");
	scanf("%d%d", &m,&n);
	printf("请输入河流的的坐标:");
	scanf("%d%d", &M, &N);
	for (i = 1; i <= m; i++){
		for (j = 1; j <= n; j++){
			if (i == M && j == N){ 
				continue;
			}
			if (i == 1 && j == 1){
				a[i][j] = 1;
			}
			else{
				a[i][j] = a[i - 1][j] + a[i][j - 1];
			}
		}
	}
	printf("A到B共有%d种不同的路线\n", a[m][n]);

	system("pause");
	return 0;
}

运行结果:
在这里插入图片描述
在这里插入图片描述

动态规划之数塔问题

问题描述
由A走到B,但每个格子对应有数字,求A走到B,数字最大为多少?
假设方格中填充的数字:
{ 0, 0, 0, 0, 0 },
{ 0, 5, 18, 4, 20 },
{ 0, 22, 15, 9, 10 },
{ 0, 14, 16, 12, 21 },
{ 0, 19, 8, 11, 6 }
思路:
要求出当前位置的最大值,必须知道上面和左边的哪一个大,然后与当前位置进行相加


#include <stdio.h>
#include <stdlib.h>

int main () {
	int a[5][5] = {
		{ 0, 0, 0, 0, 0 },
		{ 0, 5, 18, 4, 20 },
		{ 0, 22, 15, 9, 10 },
		{ 0, 14, 16, 12, 21 },
		{ 0, 19, 8, 11, 6 }
	};
	int i = 0, j = 0;
	for (i = 1; i <= 4;i++) {
		for (j = 1; j <= 4;j++) {
			if (a[i-1][j]>a[i][j-1]) {
				a[i][j] += a[i - 1][j];
			}
			else {
				a[i][j] += a[i][j-1];
			}
		}
	}
	printf("最大数字为: %d\n",a[4][4]);
    system ("pause");
    return 0;
}

运行结果:
在这里插入图片描述

动态规划之青蛙跳台

问题描述:

一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个n级台阶总共有多少种跳法。

解题思路:

找到递推公式: 台阶数: 跳法: 1 1jump1 2 2jump2 3 3jumpn 4 5 5 8 ‘’’’
根据得到的递推公式能够很明显的得到 当台阶数从第3层开始每上升一层就是前两层之和 (实际上也就类似于斐波那契数)
*递归:

#include <stdio.h>
#include <stdlib.h>

int jump(int n) {
	if (n == 1)
		return 1;
	if (n == 2)
		return 2;
	return jump(n - 1) + jump(n - 2);
}

int main () {
	printf("%d\n",jump(10));
    system ("pause");
    return 0;
}

运行结果:
在这里插入图片描述

非递归:

#include <stdio.h>
#include <stdlib.h>

int jump(int n) {
	if (n == 1)
		return 1;
	if (n == 2)
		return 2;
	int jump1 = 1;
	int jump2 = 2;
	int jumpn;
	for (int i = 3; i <= n;i++) {
		jumpn = jump1 + jump2;
		jump1 = jump2;
		jump2 = jumpn;
	}
	return jumpn;
}

int main () {

	printf("%d\n", jump(5));
    system ("pause");
    return 0;
}

运行结果:
在这里插入图片描述
拓展:
假如依次能跳1个台阶或者2个台阶或者3个台阶,求一共有n个台阶时,一共有多少种跳法?
台阶数: 跳法 : 1 1 2 2 3 3 4 6…


#include <stdio.h>
#include <stdlib.h>

int jump(int n) {
	if (n == 1)
		return 1;
	if (n == 2)
		return 2;
	if (n == 3)
		return 3;
	return jump(n - 1) + jump(n - 2) + jump(n - 3);
}

int main () {
	printf("%d\n",jump(4));
    system ("pause");
    return 0;
}

运行结果:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值