zoukankan      html  css  js  c++  java
  • LCIS最长公共上升子序列

    最长公共上升子序列LCIS,如字面意思,就是在对于两个数列A和B的最长的单调递增的公共子序列。

    这道题目是LCS和LIS的综合。

    在LIS中,我们通过两重循环枚举当序列以当前位置为结尾时,A序列中当前位置之前的数是否比当前位置的数大为条件,进行对于“最长上升子序列”的长度的转移。

    方程简单的表示为:f[i] = max{f[i], f[j +1]}(0 <= j < i)

    边界为f[0] = 0, 目标为max{f[i]}(1 <= I <= N)

    在LCS中,我们使用二维数组,对于状态“f[i, j]表示前缀子串a[1 ~ i]和b[1 ~ j]的最长公共子序列的长度”,将阶段划分为已经处理的前缀长度,f[Ii, j]的长度转移为f[i - 1][j]和f[i][j - 1]的长度,即i的上一位置得到的最长公共子序列长度与当前位置j的前一个位置的最长公共子序列长度,当a[i] == b[j]是,我们还要比较f[i][j]与f[i - 1][j - 1] +1的长度,即a序列与b序列在前一位置的最长公共子序列长度向后扩展1的总长度与当前位置所能够得到的最长公共子序列的长度进行比较,更新最长公共子序列长度

    对于LCIS,最长公共上升子序列,我们首先要解决的是公共,然后在解决上升,综合LIS和LCS解法,我们容易得到一个三重循环的写法。

    F[I, j]表示A1~Ai与B1~Bj可以构成以Bj为结尾的LCIS的长度。

    假设A0 = B0= -∞。

    当Ai != Bj时,有f[i, j] = f[i – 1, j]

    当Ai == Bj时,有

             F[i, j] = max{f[i – 1, k]} + 1(0 <= k < j, Bk < Bj) = max(f[i – 1, k]) + 1(0 <= k <j, Bk < Ai)

    这样我们很容易就能把代码写出来

    for(int i = 1; i <= n; ++i) 
        for(int j = 1; j <= m; ++j) {
            if(a[i] == b[j]) 
                for(int k = 0; k < j; ++k)
                    if(b[k] < a[i])  f[i][j] = max(f[i][j], f[i - 1][k] + 1);
            else f[i][j] = f[i - 1][j];
        }

    但是三重循环显然不是一个优秀的解法,我们思考如何优化。

    在转移过程中,我们把满足0 <= k < j并且Bk < Ai的k构成的集合称为f[i, j]进行状态转移时的决策集合,记为s[i, j],注意到当第二层循环j增加到m时,j是个定值, 这使得条件Bk小于Ai是固定的,也就是说对于决策集合s[i, j]中的k,Bk小于当前层的Ai是不会有变动的

    因此,当变量j增加1是,k的范围变为0 <= k < j + 1,即整数j可能会进入新的决策集合,也就是说,我们只需要O(1)判断Bj < Ai是否满足即可,已经在决策集合中的数则一定不会被去除….(emmm好难懂,终于想通了),再详细的说就是,当j增加1时,对于k,实际取值变化只是右端多加了1,所以我在填充决策集合时,实际上只需要对刚刚增大的j值进行判断就行了,也就是直接判断Bj < Ai是否成立来判断能否加入决策集合

                       s(i, j +1) = <1> s(i, j) (Bj >= Ai)

                                         <2> s(i, j) ∪ {j} (Bj < Ai)

    所以上述状态转移方程只需要两重循环即可求解

    1 for(int i = 1; i <= n; ++i) {
    2     int val = 0;//val是决策集合s(i, j)中f[i - 1][k]的最大值
    3     if(b[0] < a[i]) val = f[i - 1][0];//j = 1时,0可以作为b的取值
    4     for(int j = 1; j <= m; ++j) {
    5         if(a[i] == b[j]) f[i][j] = val + 1;
    6         else f[i][j] = f[i - 1][j];
    7         if(b[j] < a[i]) val = max(val, f[i - 1][j]);//j即将增大为j + 1,检查j能否进入决策集合
    8     }
    9 }

     从这道题的优化中,我们可以总结到,在实现状态转移方程时,要注意观察决策集合的范围随着状态的变化情况,对于“决策集合中的元素只增多不减少”的情景,就可以像本体一样维护一个变量来记录决策集合的当前信息,避免重复扫描,把转移的复杂度降低一个量级

  • 相关阅读:
    XidianOJ 1099 A simple problem
    XidianOJ 1097 焊板子的xry111
    XidianOJ 1172 Hiking
    XidianOJ 1176 ship
    bzoj1912(树的直径)
    黑暗城堡(最短路径树)
    poj1639(k限制最小生成树)
    0-1分数规划
    tyvj1391(Kruskal)
    [Usaco2007 Nov]Cow Relays(矩阵乘法+floyd)
  • 原文地址:https://www.cnblogs.com/ywjblog/p/8917816.html
Copyright © 2011-2022 走看看