Day21:算法篇之动态规划dp

一、有关动态规划:

1.dp思想:

    ①把一个问题分解成若干个子问题(和贪心算法思想很是类似)
    ②将中间结果保存以避免重复计算

2.基本步骤:  

        ①找出最优解的性质,然后刻画结构特征  (找规律)
        ② 最优解(最好的解决方案 定义)   循环(递归)
        ③以自上而下或者自下而上的方式来计算最优值(局部的)
        ④ 通过最优值来构造最优解

二、典例分析: 

        1.走台阶问题:

                指路:面试题10- II. 青蛙跳台阶问题(动态规划,清晰图解) - 青蛙跳台阶问题 - 力扣(LeetCode)icon-default.png?t=M7J4https://leetcode.cn/problems/qing-wa-tiao-tai-jie-wen-ti-lcof/solution/mian-shi-ti-10-ii-qing-wa-tiao-tai-jie-wen-ti-dong/

 

走台阶问题:斐波那契数列
    有N个台阶
    走法:两种   一种 一次走一阶A  二种 一次走两阶B
    问:走完N个台阶共有多少种走法
    N:10
1        2        3        4        5        6        7        8        9        10
N为1:    2种走法
N为2:    3种走法     AA   B  AB 
N为3:    5种走法        AAA AB BA BB AAB   。。。
类似的:
    兔子问题:
        已知一对兔子  从第3个月起每月会生一对兔子  请问一开始有一对兔子  怎么变的

         1  1  2  3  5  8  13 

         A  A   AB ABC ABCDE 
         A兔子 第三个月生B 第四个月生C 第五个月生D
         B兔子 第五个月生E

//台阶问题 阶数
int taijie(int n);
 
int taijie(int n)
{
	if (n < 1) return 0;
	if (1 == n) return 1;
	if (2 == n) return 2;
	//return taijie(n - 1) + taijie(n - 2);  ---->递归求解
	int f1 = 1;//第一个
	int f2 = 2;//第二个
	int temp;  //要求的和 循环求后面的
 
	for (int i = 3; i <= n; i++)//---->使用dp求解
    {
		temp = f1 + f2;
		f1 = f2;//f1和f2变化
		f2 = temp;
	}
	return temp;
}

        2. 求最短路径问题

    有矩阵    map            能且只能两种走法    往下   或者 往右   求最短路径(3作为起点)
        一        二        三        四        五
一        0        0        0        0        0
二        0        3        6        2        1
三        0        4        3        0        6
四        0        5        5        4        3        
五        0        9        7        2        8.

      用贪心算法的思想:A星寻路算法,深度寻路算法

      用dp:(看左边来还是上边来更好的,存储最优的方式(值))

             准备一个二维数组把问题转换为:以最小的方式从一个点到某一个点,中间结果保存

 

int map[5][5] = 
{
	{ 0, 0, 0, 0, 0 },
	{ 0, 3, 6, 2, 1 },
	{ 0, 4, 3, 0, 6 },
	{ 0, 5, 5, 4, 3 },
	{ 0, 9, 7, 2, 8 }
};
int min(int a, int b);
//求最短路径
int findMinPath();
 
int min(int a, int b)
{
	return ((a < b) ? a : b);
}
int findMinPath()
{
	int dp[5][5] = { 0 };
 
	for (int i = 1; i < 5; i++)
    {//从左往右 或者先往下再往右 从左上角开始求最小路径
		for (int j = 1; j < 5; j++)
        {//从上往下
            //第一行第一列
			if (i == 1)
            {//只有从左边来的可能
				dp[i][j] = dp[i][j - 1] + map[i][j];//前面的+本身的 dp数组中的+地图数组中的==现在dp数组的
			}
			else if (j == 1)
            {//只有从上边来的可能
				dp[i][j] = dp[i-1][j] + map[i][j];//上面的+本身的 dp数组中的+地图数组中的==现在dp数组的 3 + 4 == 7
			}
			else
            {//既有可能从左边来 也有可能从上边来 哪个小就加哪个 7+3? 9+3?
				dp[i][j] = min(dp[i][j - 1], dp[i - 1][j]) + map[i][j];
			}
		}
	}
	return dp[4][4];//循环后的返回值
}
 
24

        3.求最大上升串长度问题:

 例如有如下一个字符串:
        1    4    7    2    5    8    3    6    9
        上升子串  长度
        1 4 7 8 9     5
        1 2 5 8 9     5
        1 2 5 6 9     5
        1 2 3 6 9     5
        1 8 9           3
        9                 1
        1 4 5 6 9     5

把问题分解为 从左往右 到当前下标位置 比当前位置数据小的数据 的最大上升子串长度

pBuff             0        1        4        7        2        5        8        3        6        9
pMaxLen      零       一      二      三      二       三      四       三      四       五

                               1       14     147     12     125   1478    123

找当前位置前面比它要小的数中间对应最大子串长度最大的那个 + 1 == 当前位置的最大子串长度

5 找比它小的数有:1、2、4,找1、2、4中间最大子串长度最大的那个 + 1 == 5 的最大子串长度

找前面   pBuff 中数据比  当前数据要小的子集中,pMaxLen 中数据对应值最大的那个

#include <iostream>
using namespace std;
//求最大上升子串长度问题
void findMaxStrLen();
//求最大上升子串长度问题
void findMaxStrLen()
{
	int N;//要求用户输入字符串长度
	cout << "请输入串长度:";
	cin >> N;
	int* pBuff = new int[N];//用来存储串
	cout << "请输入串:";
	for (int i = 0; i < N; i++)
    {
		cin >> pBuff[i];
	}
 
	int* pMaxLen = new int[N];//临时数组存储当前位置的最大上升子串长度
	memset(pMaxLen, 0, N*sizeof(int));//初始化为0
 
	//第一个是0 从第二个开始一个个来求
	pMaxLen[1] = 1;
 
	int i, j;
	for (i = 2; i < N; i++)
    {//从第三个开始
		int nTemp = 0;//用来实时记录最大的上升子串长度
		for (j = 1; j < i; j++)
        {//从i前面的里面去找
			if (pBuff[j] < pBuff[i])
            {//数据要比当前数据小
				if (nTemp < pMaxLen[j])
                {//用nTemp来记录最大的
					nTemp = pMaxLen[j];
				}
			}
			pMaxLen[i] = nTemp + 1;
		}
	}
 
	cout << "最大上升子串长度为:" << pMaxLen[N - 1] << endl;
	cout << "MaxLen:";
	for (int k = 0; k < N; k++)
		cout << pMaxLen[k] << " ";
	cout << endl;
 
	delete[] pBuff;
	delete[] pMaxLen;
}
 
/*输出*/
 
请输入串长度:10
请输入串:0 4 7 2 5 8 3 6 9
最大上升子串长度为:5
MaxLen:0 1 2 3 2 3 4 3 4 5
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_Ocean__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值