动态规划

动态规划

  • 数字三角形

    用递归实现,复杂度为2^n

    # include<iostream>
    //max函数在algorithm头文件里
    # include<algorithm>
    using namespace std;
    
    #define MAX 101;
    int N;
    int D[MAX][MAX];
    
    int maxSum(int i,int j){
        if(i == N) return D[i][j];
        else{
            return max(maxSum(i+1,j),maxSum(i+1,j+1])+D[i][j];
        }
    }
    int main(){
        cin >> N;
        for(int i = 0;i<N;i++){
            for(int j = 0;j<=i;j++){
                cin >> D[i][j];
            }
        }
        cout << maxSum(0,0);
    }
    
  • 使用动态规划来做

    #include<iostream>
    #include<algorithm>
    #define MAX 101
    using namespace std;
    int N;
    int D[MAX][MAX];
    //一个记录中间运算结果的数组
    int maxSum[MAX][MAX];
    
    int MaxSum(int i,int j){
        //如果已经算过一次,无需再次计算,避免了重复计算降低复杂度
        if(maxSum[i][j] != -1) return maxSum[i][j];
        //如果为最后一行,D[i][j]的值就是maxSum[i][j]的值
        if(i==N) maxSum[i][j] = D[i][j];
        else{
            maxSum[i][j] = max(MaxSum(i+1,j),MaxSum(i+1,j+1))+D[i][j];
        }
        return maxSum[i][j];
    }
    int main(){
        cin >> N;
        for(int i = 0;i<N;i++){
            for(int j = 0;j<= i;j++){
                cin >> D[i][j];
                //给存储中间数据的数组赋一个不可能的初值
                maxSum[i][j] = -1;
            }
        }
        cout << MaxSum(0,0);
    }
    
    • 因为递归要用到函数调用,我们可以直接用递推做,不用调用函数,提高效率

    • 而且递归可能存在递归深度太大,堆栈不够用的情况

#include<iostream>
#include<algorithm>
#define MAX 100
using namespace std;

int N;
int D[MAX][MAX];
int maxSum[MAX][MAX];

int main(){
    cin >> N;
    for(int i = 0;i<N;i++){
        for(int j = 0;j<=i;j++){
            cin >> D[i][j];
        }
    }
    //边界值——最后一行是确定的
    for(int j = 0;j<N;j++){
        maxSum[N][j] == D[N][j];
    }
    //往上递推
    for(int i = n-1;i>=0;i--){
        for(int j = 0;j<=i;j++){
            maxSum[i][j] = max(maxSum[i+1][j],maxSum[i+1][j+1])+D[i][j];
        }
    }
    cout << maxSum[0][0];
}
  • 进一步,可以进行空间优化,使用以为数组存储maxSum,因为里面的数是滚动更新的;

  • 这也体现了递推的一个优势——有时候可以使用滚动数组

#include <iostream>
#include <algorithm>
#define MAX 100
using namespace std;
int D[MAX][MAX];
int n;
int main(){
    cin >> n;
    for(int i = 0;i<n;i++){
        for(int j = 0;j<=i;j++){
            cin >> D[i][j];
        }
    }
    int * sumMax;
    //建立一个指针指向D[n],把递推的过程变成更新D[n]中的数
    sumMax = D[n];
    for(int i = n-1;i>=0;i--){
        for(int j = 0;j<=i;j++){
            sumMax[j] = max(sumMax[j],sumMax[j+1]) + D[i][j];
        }
    }
    cout << sumMax[0];
}
  • 最长上升子序列问题

    #include <iostream>
    #include <algorithm>
    #define MAX 1000
    using namespace std;
    int a[MAX];
    //建立 一个数组来存放每一个状态
    int maxLen[MAX];
    int n;
    int main(){
       cin >> n;
       for(int i = 0;i<n;i++){
           cin >> a[i];
           maxLen[i] = 1;
       }
       for(int i = 1;i<n;i++){
           for(int j = 0;j<i;j++){
               //maxLen[]是不断更新的,max函数控制是否要更新maxLen
               if(a[i]>a[j]) maxLen[i] = max(maxLen[i],maxLen[j]+1);
           }
       }
        //输出maxLen[](容器)中最大的一个,第一个参数为起始,左闭右开;在头文件algorithm中
        cout << * max_element(maxLen,maxLen+n);
    }
    
    • 最长子串问题
#include<iostream>
#include<cstring>
#include<algorithm>
#define MAX 1000
using namespace std;

char str1[MAX];
char str2[MAX];
//有两个
int maxLen[MAX][MAX];
int main(){
    while (cin >> str1 >> str2)
    {
        int lenth1 = strlen(str1);
        int lenth2 = strlen(str2);
        int nTmp;
        int i,j;
        //先确定边界状态
        for(i = 0;i < lenth1;i++){
            maxLen[i][0] = 0;
        }
        for(j = 0;j < lenth2;j++){
            maxLen[0][j] = 0;
        }
        //递推式,这里是难点
        for(int i = 1;i<lenth1;i++){
            for(int j = 1;j<lenth2;j++){
                //这里如果不用i-1第一个字母相同不会记录
                if(str1[i-1] == str2[j-1]){
                    maxLen[i][j] = maxLen[i-1][j-1] +1;
                }else{
                //证明,maxLen[i][j]不小于其中的任何一个也不大于其中的任何一个
                    maxLen[i][j] = max(maxLen[i-1][j],maxLen[i][j-1]);
                }
            }
        }
           cout << maxLen[lenth1-1][lenth2-1] << endl;
          
    }
    return 0;
}
  • 动态规划问题最难的地方是

    设计状态,找到状态转移的递推关系式

    设计状态的原则:

    是原问题子问题的解

    具有最有子结构(原问题的最优解所包含的子问题,解也是最优的)

    无后效性(只跟当前状态有关,而与怎么抵达这个状态无关)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353

推荐阅读更多精彩内容