动态规划算法思想:
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 4 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 3 9 11 12
三 0 7 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