zoukankan      html  css  js  c++  java
  • 动态规划基础

    刚开始学DP,感觉很多DP转移方程很难理解...所以来补一补DP基础,从头捋一遍。

    1.什么是DP?动态规划(dynamic programming)是运筹学的一个分支,是求解决策过程(decision process)最优化的数学方法。-----百度百科

    这个定义看了让人更不懂了...我的理解就是,DP实际上是一种递推的记忆化搜索,它通过初始条件一步步递推,最终得到最优解。它不是一种特定的算法,而是一种思想,就像搜索一样。

    来看看别人的定义:动态规划算法通常基于一个递推公式及一个或多个初始状态。 当前子问题的解将由上一次子问题的解推出。使用动态规划来解题只需要多项式时间复杂度, 因此它比回溯法、暴力法等要快许多。

    2.DP基本原理:找到某个状态的最优解,再基于这个状态得到下一个状态的最优解,最终得到最优解。

    3.DP基本应用:

    (1)先来一道最基本的,POJ 1163 http://poj.org/problem?id=1163 数字三角形

    题意:

     

    7
    3 8
    8 1 0
    2 7 4 4
    4 5 2 6 5
    在上面的数字三角形中寻找一条从顶部到底边的路径,使得路径上所经过的数字之和最大。路径上的每一步都只能往左下或 右下走。只需要求出这个最大和即可,不必给出具体路径。 三角形的行数大于1小于等于100,数字为 0 - 99

    输入格式:

        5      //表示三角形的行数    接下来输入三角形

        7

        3   8

        8   1   0

        2   7   4   4

        4   5   2   6   5

        要求输出最大和

    解法:我们可以用一个二维数组D[][]储存三角形各个位置的数,D[i][j]表示第i行第j个数。再定义一个二维数组MaxSum[][]用于储存某个状态的最大和,MaxSum[i][j]表示点(i,j)到底边的最大和。

    从D[i][j]出发,只能到达D[i+1][j]或者D[i+1][j+1],所以可以得出递推式:

    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)

    可以得到如下递归代码:

    int MaxSum(int i, int j){      
        if(i==n)    
            return D[i][j];      
        int x = MaxSum(i+1,j);      
        int y = MaxSum(i+1,j+1);      
        return max(x,y)+D[i][j];    
    }  

    显然,对于每一行的某个数字,它都有两种选择可以到达下一个状态,所以这样做的时间复杂度是O(2^n)的,TLE。

    所以要用记忆化的方式加速程序进行速度。

    记忆化递归代码如下:

    int maxSum[MAX][MAX];  
    int MaxSum(int i, int j){        
        if( maxSum[i][j] != -1 )           
            return maxSum[i][j];        
        if(i==n)     
            maxSum[i][j] = D[i][j];       
        else{      
            int x = MaxSum(i+1,j);         
            int y = MaxSum(i+1,j+1);         
            maxSum[i][j] = max(x,y)+ D[i][j];       
        }       
        return maxSum[i][j];   
    }   

    但我们不能满足于此,递归总是需要使用大量空间的,很可能造成栈溢出,所以我们还要想办法将递归转换成递推。

    因为题目最终是要回到最后一行的,所以我们可以从最后一行出发,向上递推。

    最后一行是4 5 2 6 5,对于其上面一行的2,它可以与4相加也可以与5相加,显然与5相加得到的状态更优。依次进行这种操作,可以得到倒数第二行7 12 10 10.

    最后,我们可以得到新的三角形数表

    30

    23 21

    20 13 10

    7 12 10 10

    4 5 2 6 5

    仔细想一想,其实我们不必用二位数组存放最大和,用一个一维数组MaxSum[100]储存一行的最大和即可。更进一步的,我们可以直接用D的最后一行作为最大和数组。

    #include <iostream>    
    #include <algorithm>   
    using namespace std;   
    #define MAX 101    
    int D[MAX][MAX];    
    int n;   
    int * maxSum;   
    int main(){      
        int i,j;      
        cin >> n;      
        for(i=1;i<=n;i++)     
            for(j=1;j<=i;j++)          
                cin >> D[i][j];     
        maxSum = D[n]; //maxSum指向第n行      
        for( int i = n-1; i>= 1;  --i )       
            for( int j = 1; j <= i; ++j )         
                maxSum[j] = max(maxSum[j],maxSum[j+1]) + D[i][j];      
        cout << maxSum[1] << endl;    
    }  

    4.DP总结

    一般思路:

    (1).将原问题分解为形式相似、规模更小的子问题,得出子问题的局部最优解,进而得出最优解。

    子问题的局部最优解得出后需要保存,这样每个子问题只需要处理一次即可。

    (2).确定状态。什么是状态?我们往往把与子问题相关的一系列变量取值称之为状态,这个状态的值就是这个子问题的最优解。

    整个问题的时间复杂度是状态数目乘以计算每个状态所需时间。在数字三角形里每个“状态”只需要经过一次,且在每个状态上作计算所花的时间都是和N无关的常数。

    (3).确定边界状态的值。在数字三角形中,边界就是最后一行的数字。

    (4).确定转移方程。得到某个状态后,我们需要一个转移方程来得到下一个状态。


     

    5.

    能用动规解决的问题的特点

    1) 问题具有最优子结构性质。如果问题的最优解所包含的 子问题的解也是最优的,我们就称该问题具有最优子结 构性质。

    2) 无后效性。当前的若干个状态值一旦确定,则此后过程的演变就只和这若干个状态的值有关,和之前是采取哪种手段或经过哪条路径演变到当前的这若干个状态,没有关系。

     

     

  • 相关阅读:
    集RTMP, HLS, FLV, WebSocket 于一身的网页直播/点播播放器EasyPlayer.js引用videojs无法自动播放问题解决
    HLS播放器RTSP播放器支持8K播放且低延时高并发全功能流媒体播放器EasyPlayer搭建之HTML中 px,em,rem该如何区别?
    网页全终端安防视频流媒体播放器EasyPlayer.js如何实现在web浏览器播放H.265编码视频?
    网页全终端视频流媒体视频直播/点播播放器EasyPlayer.js实现WEB播放H265/HEVC视频方案介绍
    网页全终端视频流媒体播放器EasyPlayer之使用 nginx 和 rtmp 插件搭建视频直播和点播服务器
    车辆实时监控项目中数字摄像头和模拟摄像头的运用、区别及优势分析
    音视频流媒体服务器直播点播平台在车辆实时监控系统中如何做用户观看限制?
    如何借助CDN解决在线教育带宽小、访问大、网点分布不均等问题
    关于区块链,看看诺奖得主是如何评说的!
    区块链也有随机性!
  • 原文地址:https://www.cnblogs.com/zz990728/p/8900745.html
Copyright © 2011-2022 走看看