动态规划入门理解

自己刚刚学习了一下动态规划的思想,属入门级,总结如下:

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


 
 动态规划中,我们要找到某个状态的最优解,然后在它的帮助下,找到下一个状态的最优解。

  举例:
    问题描述:如果我们有面值为1元、3元和5元的硬币若干枚,如何用最少的硬币凑够11元?
    问题分析:我们思考,如何用最少的硬币凑够i元(i<11)。原因:大问题变小,好分析;但小问题的性质必须和大问题一致。
    分析步骤:
          i=0: d[0] = 0;
          i=1:只能使用1元的硬币:d[1] = d[1-1]+1 = d[0]+1 = 1; d[1] = 1;
          i=2:只能使用1元的硬币:d[2] = d[2-1]+1 = d[1]+1 = 2; d[2] = 2;
          i=3:     使用1元的硬币:d[3] = d[3-1]+1 = d[2]+1 = 3;
               使用3元的硬币:d[3] = d[3-3]+1 = d[0]+1 = 1;
                      so, d[3] = min{d[3-1]+1, d[3-3]+1};d[3] = 1;
         i=4:        使用1元的硬币:d[4] = d[4-1]+1 = d[3]+1 = 2;
                 使用3元的硬币:d[4] = d[4-3]+1 = d[3]+1 = 2;
                     so, d[4] = min{d[4-1]+1, d[4-3]+1};d[4] = 2;

    
小结:状态: 凑够i元 所需的硬币数量;
            状态只与它前面出现的状态有关,独立于后面的状态。
    状态转移方程:描述状态之间是如何转移的,d[i] = min{d[i-Vj]+1},其中 i-Vj >= 0;Vj是下一个可取的决策值。

    

int MaxValue(int **A, int row, int col)
{
    int **s = new int*[row];
    for (int i =0 ; i < row; i++)
    {
        s[i] = new int[col];
    }
    int temp=0;
    
    for (i = 0; i<row; i++)
    {
        for (int j = 0; j < col; j++)
        {
            temp = 0;
            s[i][j] = A[i][j];
            if (j>0)
            {
                temp = A[i][j-1];
            }
            if (i>0 && A[i-1][j] > temp )
            {
                temp = A[i-1][j];
            }
        }
    }
    temp = s[row-1][col-1];
    
    for (i  = 0; i < row; i++)
    {
        delete s[i];
    }
    delete [] s;
    s=NULL;

    return temp;
}

 


  举例:
    问题描述:LIS:longest increasing subsequence(最长非降序子序列), A[1], A[2]....A[N]
    问题分析:
    找状态:求A[1], A[2]....A[i](i<N) 中的最长非降序子序列。
    状态转移方程:d[i] = max{1, d[j]+1}, j<i, A[j]<=A[i];

    

int LIS(int *arr, int n)
{
    int *d = new int[n];
    int len = 1;;
    memset( d, 0, n);
    for (int i = 0; i < n; i++)
    {    
        d[i] = 1;
        for (int j = 0; j <i; j++)
        {
            if(arr[j] <= arr[i] && d[i] < d[j] + 1)
            {
                d[i] = d[j] + 1;
            }
        }
        if (d[i] > len)
        {
            len = d[i];
        }
    }
    delete[] d;
    d = NULL;
    
    return len;
}
LIS

 

  举例:
    问题描述:平面上有N*M个格子(A[N][M]),每个格子中放着一定数量的苹果。你从左上角的格子开始, 每一步只能向下走或是向右走,
          每次走到一个格子上就把格子里的苹果收集起来, 这样下去,你最多能收集到多少个苹果。
    问题分析:
    找状态:s[i][j],走到 i,j 时收集到的苹果数量
    状态转移方程:s[i][j] = A[i][j] + max(S[i-1][j], if i>0 ; S[i][j-1], if j>0)

    代码如下:

int MaxValue(int **A, int row, int col)
{
    int **s = new int*[row];
    for (int i =0 ; i < row; i++)
    {
        s[i] = new int[col];
    }
    int temp=0;
    
    for (i = 0; i<row; i++)
    {
        for (int j = 0; j < col; j++)
        {
            temp = 0;
            s[i][j] = A[i][j];
            if (j>0)
            {
                temp = A[i][j-1];
            }
            if (i>0 && A[i-1][j] > temp )
            {
                temp = A[i-1][j];
            }
        }
    }
    temp = s[row-1][col-1];
    
    for (i  = 0; i < row; i++)
    {
        delete s[i];
    }
    delete [] s;
    s=NULL;

    return temp;
}
代码

 

posted on 2015-09-20 11:12  OrdinaryMiracle  阅读(232)  评论(0编辑  收藏  举报

导航