动态规划经典问题总结

动态规划解法一般分以下几步:
* 描述最优子结构
* 列出状态转移方程
* 从上而下递归求解 或者从下而上递推求解
一般情况下使用递推求解比较方便,最优子结构的描述影响着求解的方式

以下是动态规划经典问题:
最大连续子序列和问题
子结构描述: sum[i] 表示以i结尾最大连续子序列和
状态转移方程 sum[i] = max(sum[i-1]+a[i], a[i])
代码如下:

   int largest_array(int *array, int len){
    int sum = array[0], res = array[0];
    for(int i = 1; i < len; i++){
        if(sum+array[i] > array[i])
            sum = sum+array[i];
        else
            sum = array[i];
        if(sum > res)
            res = sum;
    }
    return res;
}

数字三角形问题
子结构描述:dp[i][j]从点(i, j)到底的最大值
状态转移方程:dp[i][j] = max(dp[i+1][j], dp[i+1][j+1])+a[i][j]
代码如下:

   //使用递推的方法来解决
int DP[100][100];
int num;
int maxSum(int i, int j){
    if(i == num)
        return DP[i][j];
    int tmp1 = maxSum(i+1, j)+DP[i][j];
    int tmp2 = maxSum(i+1, j+1)+DP[i][j];
    return max(tmp1, tmp2);
}

//不使用递推的方法来解决
int maxSum2(){
    int i, j;
    for(i = num-1; i <= 1; i--)
        for(j = 1; j <= i; j++){
            DP[i][j] = max(DP[i+1][j], DP[i+1][j+1])+DP[i][j];
        }
    return DP[1][1];
}

背包问题1:背包大小为m,有n个物品,最多能放多重
子结构描述:dp[n][m] 表示背包只放前个n,包容量m, 实际能放多重
代码如下:

   int w[n];
int package(int m, int n){
    int dp[n+1][m+1];
    for(int i = 0; i < n+1; i++)
        dp[i][0] = 0;
    for(int i = 0; i < m+1; i++)
        dp[0][i] = 0;
    for(int i = 1; i < n+1; i++)
        for(int j = 1; j < m+1; j++){
            if(j > w[i-1])
                dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i-1]]+w[i-1]);
            else
                dp[i][j] = dp[i-1][j];
        }
    return dp[n][m];


}

背包问题2:背包大小m, 体积大小A[i], 价值大小V[i] 此时我们记录的是价值
此时只是:dp[n][m]语义变了,表示能放最大价值为多少
代码如下:

  int w[n], v[n];
int package(int m, int n){
        int dp[n+1][m+1];
    for(int i = 0; i < n+1; i++)
        dp[i][0] = 0;
    for(int i = 0; i < m+1; i++)
        dp[0][i] = 0;
    for(int i = 1; i < n+1; i++)
        for(int j = 1; j < m+1; j++){
            if(j > w[i-1])
                dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i-1]]+v[i-1]); //仅仅将重量换成价值
            else
                dp[i][j] = dp[i-1][j];
        }
    return dp[n][m];
}

LCS 最长公共子序列问题 a[n] b[n] 表示两个序列的长度
状态转移方程:
dp[i][j] = dp[i-1][j-1]+1 where a[i] = b[j]
dp[i][j] = max(dp[i-1][j], dp[i][j-1])
代码如下:

    char a[n], b[m];
int longest_seq(int n, int m){
    int dp[n+1][m+1];
    for(int i = 1; i < n+1; i++)
        for(int j = 1; j < m+1; j++){
            if(a[i-1] == b[j-1])
                dp[i][j] = dp[i-1][j-1]+1;
            else
                dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
        }
    return dp[n][m];
}

最长公共子串问题
dp[i][j] 表示以i j结尾最长子串的长度
代码如下:

  int longest_sub(int n, int m){
    int dp[n+1][m+1]; int res = 0;
    for(int i = 1; i < n+1; i++)
        for(int j = 1; j < m+1; j++){
            if(a[i-1] == b[j-1])
                dp[i][j] = dp[i-1][j-1]+1;
            else
                dp[i][j] = 0;
            if(dp[i][j] > res) res = dp[i][j];
        }
}

最长递增子序列
子结构描述:dp[j] 表示以j结尾的最长递增子序列长度
状态转移方程: dp[j] = max(dp[i]) + 1 j > i && a[j] > a[i]
代码如下:

   int longest_incre(int n){
    int dp[n]; int res = 0;
    for(int i = 0; i < n; i++)
        dp[i] = 1;
    for(int i = 1; i < n; i++){
        for(int j = 0; j < i; j++){
            if(a[i] > a[j] && dp[i] < dp[j]+1)
                dp[i] = dp[j]+1;
            if(dp[i] > res) res = dp[i];
        }
    }
    return res;
}

还有一些常见的动态规划问题:
编辑字符串距离
N皇后问题
打劫房屋

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值