一、有关动态规划:
1.dp思想:
①把一个问题分解成若干个子问题(和贪心算法思想很是类似)
②将中间结果保存以避免重复计算2.基本步骤:
①找出最优解的性质,然后刻画结构特征 (找规律)
② 最优解(最好的解决方案 定义) 循环(递归)
③以自上而下或者自下而上的方式来计算最优值(局部的)
④ 通过最优值来构造最优解
二、典例分析:
1.走台阶问题:
走台阶问题:斐波那契数列
有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