动态规划入门&字符串相关

前言

  • 什么是动态规划?

    • 动态规划是求解决策过程最优化的数学方法。把多阶段过程转化为一系列单阶段问题,利用各阶段之间的关系,逐个求解。
  • 什么时候要用动态规划?

    • 如果要求一个问题的最优解(通常是最大值或者最小值),而且该问题能够分解成若干个子问题,并且小问题之间也存在重叠的子问题,则考虑采用动态规划。
  • 动态规划的前提

    1. 最优化原理(最优子结构性质)
      • 最优化原理可这样阐述:一个最优化策略具有这样的性质,不论过去状态和决策如何,对前面的决策所形成的状态而言,余下的诸决策必须构成最优策略。简而言之,一个最优化策略的子策略总是最优的。一个问题满足最优化原理又称其具有最优子结构性质。
    2. 无后效性
      • 将各阶段按照一定的次序排列好之后,对于某个给定的阶段状态,它以前各阶段的状态无法直接影响它未来的决策
    3. 子问题的重叠性
  • 解题步骤

    1.确定题意要求的最优解是什么
    2.确定已知量有哪些
    3.根据已知量确定dp的状态有哪些维
    4.从下而上的分析问题,找到关联
    5.确定状态转移方程
    6.确定底层边界的答案
    如果出现方程无法确定的情况,比如子结构无法最优,有后效性的时候先考虑换状态

例题

一、字符串相关

  • 小概念
    • 对于一个字符串而言,比如:pikachu

    • 字串(substring):在字符串中,取出一块(连续的),如:pik, ach, kac等

    • 子序列(subsequence):从字符串中,顺序取出字符,但是可以不连续:如:pau, kch, icu等

    • 一个长度为n的字符串有[n*(n+1)]/2子串,有2^n-1子序列?(不考虑空串)

  • 最长公共子序列
    • 给两个字符串,求他们的最长公共子序列长度

    • 例如abcd和befgc的最长公共子序列的长度是2(bc)

    • 状态:设数组dp[m][n]来表示长度为m的str1和长度为n的str2的最长公共子序列长度

    • if (m[i] == n[j]) dp[i][j] = dp[i - 1][j - 1] + 1;
      else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);

int dp[10000][10000];

int main() {
    string m, n;
    cin >> m >> n;
    int cntm = m.size();
    int cntn = n.size();
    m = "\0" + m;
    n = "\0" + n;

    for (int i = 1; i <= cntm; i++)
        for (int j = 1; j <= cntn; j++) {
            if (m[i] == n[j]) dp[i][j] = dp[i - 1][j - 1] + 1;
            else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
        }
    p(dp[cntm][cntn]);
}

/* 建模
 *    b e f g c
 * a  0 0 0 0 0
 * b  1 1 1 1 1
 * c  1 1 1 1 2
 * d  1 1 1 1 2
 */
  • 最长递增子序列
    • 给定一个数列,求他的最长递增子序列长度

    • 例如:1 2 3 1 2 10的最长递增子序列长度是4(1 2 3 10)

    • 状态:dp[n]代表1-n的最长递增子序列长度

    • 方程:
      dp[n]=1;
      if(a[n]>a[m]) dp[n]=max(dp[n],dp[m]+1); m<n

const int maxn = 1e6 + 7;
int n, a[maxn], dp[maxn];//a[]储存输入的值,dp[n]为以a[n]结尾的最长递增子序列长度


int main() {
    sc(n);
    for (int i = 1; i <= n; i++) sc(a[i]);
    for (int i = 1; i <= n; i++) {
        dp[i] = 1;
        for (int j = 1; j < i; j++) {
            if (a[i] > a[j])
                dp[i] = max(dp[i], dp[j] + 1);//线段树优化,dp[i]=max{dp[j]}+1;
        }
    }
    for (int i = 1; i <= n; i++) cout << a[i] << " ";
    cout << endl;
    for (int i = 1; i <= n; i++) cout << dp[i] << " ";
}
发布了22 篇原创文章 · 获赞 0 · 访问量 479

猜你喜欢

转载自blog.csdn.net/skyyemperor/article/details/104728209