动态规划DP

动态规划算法思想:
    1. 把一个问题分解成若干个子问题
    2. 将中间的结果保存以避免重复计算
    基本步骤:
        1. 找出最优解的性质,然后刻画结构特征 (找规律)
        2. 最优解(最优值的定义) 循环 | 递归
        3. 以自下而上或者自上而下的方式来计算最优值
        4. 通过最优值最终构造一个最优解

    和贪心算法思想很是类似

走台阶问题: 斐波那契数列
    有N(10)个台阶   
    走法:  两种
        一    一次走一阶
        二    一次走两阶
    问:走完N个台阶共有多少种走法?
②                   f1       f2     temp = f1 + f2
①         f1       f2     temp = f1 + f2
台阶数   1        2        3        4        5        6        7        8        9        10

走法     一      二       三      五      八

1:走一阶有且只有一种走法

2:两次走  每次走一阶   一次走:一次走两阶

3:三次走  每次走一阶   两次走:第一次走一阶第二次走两阶    第一次走两阶第二次走一阶

4:四次走  每次走一阶   三次走:121 112 211  两次走:22

5:五次走  每次走一阶   四次走:1112 1121 1211 2111  三次走:122 212 221  两次走:无法实现

每一次走都是前两次走的和(由于走法是两种)

回退一阶或者两阶

//台阶问题 阶数
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++){
		temp = f1 + f2;
		f1 = f2;//f1和f2变化
		f2 = temp;
	}
	return temp;
}

求最短路径问题

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

        用动态规划思想:
        有格子 格子如下  图中数据为从该点出发消耗的代价、路径长度   能且只能有两种走法:往下 或者 往右  求最短(长)路径
        map
           一    二    三      四       五
    一    0      0      0       0        0
    二    0      3      6       2        1
    三    0      4      3       0        6
    四    0      5      5             3
    五    0      9      7       2        8

                                    26     29

        准备一个二维数组把问题转换为:以最小的方式从一个点到某一个点,中间结果保存
           一    二    三      四      五
    一    0      0      0       0        0
    二    0      3      0       0        0
    三    0      0      0       0        0
    四    0      0      0       0        0
    五    0      0      0       0        8
        dp
           一    二     三     四     五
    一    0      0      0       0       0
    二    0           9      11     12
    三    0         10      10      0
    四    0      0      0      14      0
    五    0      0      0      16     24

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

求最大上升子串长度问题
    例如有如下一个字符串:
        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();

int main(){
#if 0
	//台阶问题
	int n;
	
	while (1){
		cout << "请输入n:";
		cin >> n;
		cout << taijie(n) << endl;
	}
#endif
#if 0
	//求最短路径
	cout << findMinPath() << endl;
#endif
	//求最大上升子串长度问题
	findMaxStrLen();

	while (1);
	return 0;
}

//求最大上升子串长度问题
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
  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

qiuqiuyaq

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

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

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

打赏作者

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

抵扣说明:

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

余额充值