• hunnu 11313 无重复元素序列的最长公共子序列转化成最长递增子序列 求法及证明


    题目:http://acm.hunnu.edu.cn/online/?action=problem&type=show&id=11313

    湖师大的比赛,见我的另一篇水题题解,这里要说的是我YY出来的C题,无重复元素序列的最长公共子序列。

    用常规的做法会超时,于是我YY出来一个方法,记录第一组各个数字的位置,读取第二组,把第一组出现的相同数字的位置放入序列,没出现就不放。。。然后就转成LIS题目了。。。


    具体用例子来说明下,比如两个序列

    3 2 1 5 4

    2 1 5 4 3

    很明显,LCS是2 1 5 4,4个。

    那么开个初始化为-1的数组rec存放第一个序列的位置rec[i]为数字i出现的位置,-1表示没有出现(因为不能排除第二组元素在第一组没有出现的情况)。

    在这里,3出现在第1个,于是rec[3]=1,以此类推,rec[]={3,2,1,5,4}。


    读取第二个序列,将第一个序列出现的相同数字的位置放到数组lis里面,没出现就不放。

    在这里rec[2]=2,rec[1]=3...所以lis[]={2,3,4,5,1}。


    然后用n*logn求LIS,我直接用吉大的模版。。。

    求出来是4,跟答案是一样的。


    int main() {
    //    freopen("in", "r", stdin);
        int rec[maxn], lis[maxn], n, tmp;
        while (scanf("%d", &n) && n) {
            int cnt = 0;
            memset(rec, -1, sizeof(rec));
            for (int i = 1; i <= n; i++) {
                scanf("%d", &tmp);
                rec[tmp] = i;                  //存放位置
            }
            for (int i = 1; i <= n; i++) {
                scanf("%d", &tmp);
                if (rec[tmp] != -1)
                    lis[cnt++] = rec[tmp];      //生成LIS
            }
            printf("%d
    ", LIS(lis, cnt));
        }
        return 0;
    }



    证明,我也不是很懂,稍微讲讲吧。。。

    构造LIS时,第一个序列出现的相同数字的位置放到数组lis里面,LIS里面的升序就变成是序列一的顺序,而求最长递增子序列原本就是按序列的顺序求的,所以求出来的顺序也是序列二的顺序。

    而LIS取的是两个序列相同的元素,所以求出来的子序就是原来两个序列的LCS。

    额,有点牵强。。。但这是我YY出来的,挺有成就感的。。。


    其实想起来和LIS的另一种求法有点像,我以前老是用的方法:

    就是把原序列复制一遍并排序,然后求LCS。。。这种吃力不讨好的求法。。。


    That's all...


  • 相关阅读:
    BF算法和KMP算法
    Python课程笔记 (五)
    0268. Missing Number (E)
    0009. Palindrome Number (E)
    0008. String to Integer (atoi) (M)
    0213. House Robber II (M)
    0198. House Robber (E)
    0187. Repeated DNA Sequences (M)
    0007. Reverse Integer (E)
    0006. ZigZag Conversion (M)
  • 原文地址:https://www.cnblogs.com/java20130723/p/3212133.html
Copyright © 2020-2023  润新知