算法复习——动态规划

2021-03-08 20:28

阅读:370

标签:str   大于   关系   容量   背包   line   分析   大连   连续   

0-1背包问题、最大连续子数组问题、最长公共子序列、最长公共子串、最小编辑距离、钢条切割、矩阵链乘

动态规划问题的一般步骤:

  1. 给出问题的表示,明确子问题
  2. 分析最优结构,构造递推公式
  3. 确定计算顺序,依次求解问题
  4. 记录决策过程,输出最优方案

0-1背包

动规方程

\(p[i,c]\)表示前i个物品在背包容量为c时能选择的最大价值。

\(dp[i,c] = max\{dp[i-1,c-v_i] + p_i, dp[i-1,c]\}\)

所以0-1背包问题就是求\(p[n,C]\)

伪代码

//初始化
for(i=0 to C) { //前0个物品,背包容量是C时
    dp[0][i] = 0;
}
for(i=0 to n) { //前i个物品,背包容量是0时
    dp[i][0] = 0;
}
//i表示前i个物品
for(i=1 to n) {
    //j表示当前背包容量
    for(j=1 to C) {
        // 如果选择这个物品装入背包
        if ((v[i]  dp[i-1][j])){
            dp[i][j] = dp[i-1][j-v[i]] + p[i];
        }
        // 如果背包容量装不下v[i]或者装入背包后总价值变小,那么选择不装入
        else {
            dp[i][j] = dp[i-1][j];
        }
    }
}
// 选择最优的方案
return dp[n][C];

时间复杂度:\(O(n*c)\)

总结,解决0-1背包问题的思路:

  1. 有n种物品,其对应的体积为\(v_i\), 价值为\(p_i\),想要求容量为C的背包,能装下物品的最大价值,用dp[i][j]表示前i种物品,在背包容量为j的情况下能装下物品的最大价值
  2. 构造递推式,子问题和原问题之间的关系,\(dp[i,c] = max\{dp[i-1,c-v_i] + p_i, dp[i-1,c]\}\)
  3. 确定计算的顺序,就是从前往后递推
  4. 记录...

最大连续子数组问题

D[i]表示以X[i]开头的最大子数组的和,所以要从后往前计算

如果用dp[i]表示以X[i]结尾的最大子数组的和,则从前往后计算

dp[n] = X[n]
max = dp[n];
for(i=n-1 to 1) {
    //如果以X[i+1]开头的最大子数组的和dp[i+1]大于0,那么以X[i]开头的最大子数组的和dp[i]等于X[i]+ dp[i+1]
    if(dp[i+1] > 0) { 
        dp[i] = dp[i+1] + X[i];
    }
    else {
        dp[i] = X[i]
    }
    
    if(dp[i] > max) {
        max = dp[i];
    }
}
return max;

时间复杂度\(O(n)\)

最长公共子序列

原始问题:X[1..n] Y[1..m]两个字符串,求其最长公共子序列

用dp[i][j]表示X[1..i], Y[1..j]的最长公共子序列长度

递推式

\(if X[i] == Y[j]: dp[i][j] = dp[i-1][j-1] + 1;\)

\(else: dp[i][j] = max\{dp[i][j-], dp[i-1][j]\}\)

// 初始化
for(i=1 to n) {
    dp[i][0] = 0;
}
for(j=1 to m) {
    dp[0][j] = 0;
}
//
for(i=1 to n) {
    for(j=1 to m) {
        if(X[i] == Y[j]) {
            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]

时间复杂度\(O(n*m)\)

最长公共子串

子序列不要求连续,但是子串要求是连续的

递推式:

\(if X[i] == Y[j]: dp[i][j] = dp[i-1][j-1] + 1;\)

\(else: dp[i][j] = 0\)

伪代码:

// 初始化
for(i=1 to n) {
    dp[i][0] = 0;
}
for(j=1 to m) {
    dp[0][j] = 0;
}
//
for(i=1 to n) {
    for(j=1 to m) {
        if(X[i] == Y[j]) {
            dp[i][j] = dp[i-1][j-1] + 1; 
        }
        else {
            dp[i][j] = 0;
        }
    }
}
return dp[n][m]

时间复杂度\(O(n*m)\)

最小编辑距离

有点复杂,最后复习


下面这两个是同一种类型的,都需要遍历子问题

钢条切割

C[i]表示切割长度为i的钢条所能获得的最大收益

$C[i] = max_{1\le j\le i-1}{p[j] + C[i-j]], p[i]} $

c[0] = 0;
for(i=1 to n) {
    q = p[i]; // 不切割
    for(j=1 to i-1) { // 枚举子问题,找最大值
        if (p[j]+C[i-j] > q) {
            q = p[j] + C[i-j]
        }
    }
    C[i] = q;
}
return C[n]

时间复杂度为:\(O(n^2)\)

矩阵链乘

明确原始问题:

明确原始问题 ??[??, ??]:计算矩阵链????..??所需标量乘法的最小次数

递推关系建立:

分析最优(子)结构

建立动规方程:

\(dp[i][j]\)表示第i个矩阵乘到第j个矩阵所需要的最小乘法次数

\(dp[i][j] = min_{i \le k \le j-1}\{dp[i][k]+dp[k+1][j] + p_{i-1}*p_k*p_j \}\)

确定计算顺序:

dp[1..n][1..n] = INF;
for(i=1 to n) {  //如果只有一个矩阵,乘法次数为0
    dp[i][i] = 0;
}
for(l=2 to n) { // 区间长度
    for(i=1 to n-l+1) {//区间左端点
   		j = i+l-1; // 区间右端点
        for(k=i to j-1) {
            dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j] + p[i-1]*p[k]*p[j]);
        }
    }
}
return dp[1][n];

算法复习——动态规划

标签:str   大于   关系   容量   背包   line   分析   大连   连续   

原文地址:https://www.cnblogs.com/VanHa0101/p/14193114.html


评论


亲,登录后才可以留言!