• 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...


  • 相关阅读:
    快速排序
    Java LinkedList
    Java ArrayList
    Java ReentrantLock
    Java Timer
    Java 管道PipedInputStream PipedOutStream PipedReader PipedWriter
    6. Samba服务和防火墙配置笔记
    5. 网络配置与FTP服务笔记
    3.vi 和软件安装
    2 . Linux常见命令
  • 原文地址:https://www.cnblogs.com/java20130723/p/3212133.html
Copyright © 2020-2023  润新知