OVSolitario-io

导航

线性DP

线性DP:

状态维度:

  • 答案一定能表示
  • 答案可以被推出

以此为基础,维度越低越好(更少时复)

因此维度:从小->大考虑

DP存方案:记录转移即可,例子在LIS后面

LIS
考虑LIS问题,我的上一步一定是我前面的某一个值,将我接在它后面,LIS长度+1
定义:dp[i]是以i结尾的LIS长度
考虑:

  • 若j < i,aj < ai,则进行拼接

状态转移方程: 我 = 比我小的序列 + 1

从前往后顺序求解,保证了计算a[i]时,i前面allj的LISa[j]已算出,此时a[i] = a[j] + 1,考虑all情况a[i] = max(a[j] + 1);

点击查看代码
for(int i = 1; i <= n; ++ i) {
    f[i]=1;
    for(int j = 1; j < i; ++ j) {
        if(a[j] < a[i]) {
            f[i] = max(f[i], f[j] + 1);
        }
    }
    res = max(res, f[i]);
}

存方案:

点击查看代码
for(int i = 1;i <= n; ++ i)
    {
        f[i] = 1;
        g[i] = 0;
        for(int j = 1; j < i; ++ j) {
            if(a[j] < a[i]) {
                if(f[i] < f[j] + 1) {//只有更优才会存储
                    f[i] = f[j] + 1;
                    g[i] = j;//记录从哪个状态转移而来
                }
            }
        }
    }
    int k = 1;//求最优解下标,以k结尾
    for(int i = 1; i <= n; ++ i) {
        if(f[k] < f[i]) {
            k = i;
        }
    }
    printf("%d\n", f[k]);
    
    //最优解以k结尾,往回推(a[]为值,g[]为下标)
    for(int i = 0, len = f[k]; i < len; ++ i) {//输出的是方案逆序
        printf("%d ", a[k]);
        k = g[k];
    }

LIS()

LCS
两序列A,B两维表示,对于a和b序列LCS以AB结尾的LCS上一个值一定是A序列中的i,且存在B序列中的j

定义:dp[i,j]为a序列前i个字母,b序列前j个字母构成的子序列

发现对于Ai,Bj有三种可能:

  • 用Ai和Bj,if Ai = Bj
  • 不用Ai
  • 不用Bj

从前往后去看即可

点击查看代码
for(int i = 1; i <= n; ++ i) {
    for(int j = 1;j <= m; ++ j) {
        f[i][j] = max(f[i - 1][j], f[i][j - 1]);
        if(a[i] == b[j]) {
            f[i][j] = max(f[i][j], f[i - 1][j - 1] + 1);
        }
    }
}

特殊的(1 ~ n)LCS:LCS重标号转LIS问题

p2758编辑距离
2串=>2维,为将a前i个字符,变为b的前j个字符的最小操作次数

posted on 2025-10-09 20:04  TBeauty  阅读(3)  评论(0)    收藏  举报