PS:本篇博文均采用宏#define FOR(i, a, n) for(i = a; i <= n; ++i)

  • LIS:最长上升子序列

    废话不多说:http://baike.baidu.com/link?url=bRXFb18sGwPcKpplIIIq40hnngEUJe6S4b1PLgVnaby8zaahrO2NhI2tfoQZmw54#2_1 http://www.nocow.cn/index.php/%E6%9C%80%E9%95%BF%E4%B8%8D%E4%B8%8B%E9%99%8D%E5%AD%90%E5%BA%8F%E5%88%97

    设状态f(i)表示前i个数的最长上升子序列的长度,可以得到

    f(i) = max{f(j)} + 1, 其中 1 <= j < i且a[i] < a[j]

    答案就是max{f(i)}, 1<=i<=n

    CODE:

    FOR(i, 1, n) {
    f[i] = 1; //初始化
    FOR(j, 1, i-1)
    if(a[j] < a[i] && f[i] < f[j] + 1)
    f[i] = f[j] + 1, ans = max(ans, f[i]);
    }

    其实就是在前面找一个k,接上去

    然后是带路径记录的LIS,想法是,既然每次都是找f[j]来接到f[i]上,那么记录每个j,然后逆着走即可:

    #include <cstdio>
    using namespace std;
    #define FOR(i, a, n) for(i = a; i <= n; ++i) const int maxn = 5000;
    int n, a[maxn], f[maxn], i, j, ans;
    int pre[maxn], path[maxn], pos, len; void setIO() {
    freopen("in", "r", stdin);
    freopen("out", "w", stdout);
    }
    int main() {
    setIO();
    scanf("%d", &n);
    FOR(i, 1, n) scanf("%d", &a[i]);
    FOR(i, 1, n) {
    f[i] = 1; //初始化
    FOR(j, 1, i-1) //增序得出来答案是lower_bound(i)的。。
    if(a[j] < a[i] && f[i] < f[j] + 1) {
    f[i] = f[j] + 1;
    pre[i] = j; //记录接入的路径
    if(ans < f[i])
    ans = f[i], pos = i; //记录最长的开始下标
    }
    }
    printf("%d\n", ans);
    len = ans;
    if(ans > 0) path[ans--] = pos; //先加入进去,因为没有记录最后的接入路径
    while(ans && pos) {
    if(pre[pos] > 0) {
    path[ans--] = pre[pos];
    pos = pre[pos];
    }
    }
    FOR(i, 1, len) printf("%d ", a[path[i]]);
    return 0;
    }
  • LCS:最长公共子序列

    还是去看nocow把:http://www.nocow.cn/index.php/%E6%9C%80%E9%95%BF%E5%85%AC%E5%85%B1%E5%AD%90%E5%BA%8F%E5%88%97

    设f(i, j)表示a的前i个数和b的前j个数的最大公共子序列长度,有

    f(i, j) = f(i-1, j-1) + 1,  a[i] == b[j]

    f(i, j) = max{f(i-1, j), f(i, j-1)},  a[i] != b[j]

    答案是f(sa, sb),sa,sb是a和b的长度

    将这个用矩阵表示好理解,具体看nocow

    二维:

    FOR(i, 1, sa) FOR(j, 1, sb)
    if(seq1[i] == seq2[j]) f[i][j] = f[i-1][j-1] + 1;
    else f[i][j] = max(f[i-1][j], f[i][j-1]);

    由于是方程严格递增并且方程阶段是第二维,那么我们可以转化为一维的

    一维:

    FOR(i, 1, sa) FOR(j, 1, sb)
    if(seq1[i] == seq2[j]) f[j] = f[j-1] + 1;
    else f[j] = max(f[j], f[j-1]);

    那么用二维的我们还能求路径,与LIS不同的是,LCS求路径是方程的逆,逆回去即可。。。

    可以用矩阵来想

    for(i = sa, j = sb; j > 0 && i > 0;) {
    if(seq1[i] == seq2[j]) {
    path[num++] = seq1[i];
    i--; j--;
    }
    else (f[i-1][j] > f[i][j-1]) ? i-- : j--;
    }

    全套:

    #include <cstdio>
    #include <iostream>
    using namespace std;
    #define FOR(i, a, n) for(i = a; i <= n; ++i) void setIO() {
    freopen("in", "r", stdin);
    freopen("out", "w", stdout);
    }
    const int maxn = 500;
    int i, j, num, f[maxn][maxn], seq1[maxn], seq2[maxn], sa, sb;
    int path[maxn]; int max(const int& a, const int& b) { return a < b ? b : a; } int main() {
    setIO(); scanf("%d%d", &sa, &sb);
    FOR(i, 1, sa) scanf("%d", &seq1[i]);
    FOR(i, 1, sb) scanf("%d", &seq2[i]);
    FOR(i, 1, sa) FOR(j, 1, sb)
    if(seq1[i] == seq2[j]) f[i][j] = f[i-1][j-1] + 1;
    else f[i][j] = max(f[i-1][j], f[i][j-1]);
    for(i = sa, j = sb; j > 0 && i > 0;) {
    if(seq1[i] == seq2[j]) {
    path[num++] = seq1[i];
    i--; j--;
    }
    else (f[i-1][j] > f[i][j-1]) ? i-- : j--;
    }
    cout << f[sa][sb] << endl;
    for(i = num-1; i >= 0; --i) cout << path[i] << ' ';
    cout << endl;
    return 0;
    }
  • LCIS:最长公共上升子序列

    这个可以说是LCS和LIS的结合体~。我们用LIS的思想来想,3维的方法我不会。。网上也没有找到,那就只有用n^2算法把。。

    具体定义什么的可以参考前一篇博文

    这里更新一下求路径的以及一些注释

    #include <iostream>
    #include <cstdio>
    using namespace std; #define FOR(i, a, n) for(i = a; i <= n; ++i) void setIO() {
    freopen("in", "r", stdin);
    freopen("out", "w", stdout);
    }
    const int maxn = 550;
    int seq1[maxn], seq2[maxn], sa, sb;
    int f[maxn], pre[maxn][maxn], path[maxn], ans, len, maxi, temp, pos1, pos2, i, j, k;
    int max(const int& a, const int& b) { return a < b ? b : a; } int main() {
    setIO(); cin >> sa >> sb;
    FOR(i, 1, sa) cin >> seq1[i];
    FOR(i, 1, sb) cin >> seq2[i];
    ans = 0;
    FOR(i, 1, sa) {
    maxi = temp = 0; //初始化,很重要
    FOR(j, 1, sb) //求lcds将a[i] > b[j]改为a[i] < b[j]即可
    if(seq1[i] > seq2[j] && f[j] > maxi) maxi = f[j], temp = j; //得到temp = max{f[i-1][k]}
    else if(seq1[i] == seq2[j]) {
    f[j] = maxi + 1;
    pre[i][j] = temp; //能接上b[j]的b[temp],以后用答案直接索引到temp
    if(ans < f[j]) {
    pos1 = i; //记录最长公共上升seq所对应的下标i和j
    pos2 = j;
    ans = f[j];
    }
    }
    }
    cout << ans << endl;
    len = ans;
    //和LIS的路径几乎一模一样
    if(ans > 0) path[ans--] = pos2; //将最后的添上
    while(ans && pos1 && pos2) { //依据pos2(最长seq的j值)一直找
    if(pre[pos1][pos2] > 0) {
    path[ans--] = pre[pos1][pos2]; //将这些k记录下来
    pos2 = pre[pos1][pos2]; //更新接上的最大
    }
    pos1--; //因为要的是max{f[i-1][k]},所以要倒着i-1回去找,即f[i-1][k],记录的k值
    }
    FOR(i, 1, len) cout << seq2[path[i]] << ' ';
    cout << endl; return 0;
    }

LIS+LCS+LCIS的更多相关文章

  1. 8.3 LIS LCS LCIS(完结了==!)

    感觉这个专题真不好捉,伤心了,慢慢啃吧,孩纸 地址http://acm.hust.edu.cn/vjudge/contest/view.action?cid=28195#overview 密码  ac ...

  2. LIS LCS LCIS (主要过一遍,重在做题)

    只详细讲解LCS和LCIS,别的不讲-做题优先. 菜鸟能力有限写不了题解,可以留评论,我给你找博客. 先得理解最长上升子序列吧,那个HDOJ拦截导弹系列可以做一下,然后用o(n)log(n)的在做一遍 ...

  3. LIS && LCS && LCIS && LPS && MCS模板

    1. LIS (Longest Increasing Subsequence) O (n^2): /* LIS(Longest Increasing Subsequence) 最长上升子序列 O (n ...

  4. LIS&&LCS&&LCIS

    LIS #include<bits/stdc++.h> using namespace std; int n,a[100005],b[100005],ji; int main(){ cin ...

  5. 线性DP总结(LIS,LCS,LCIS,最长子段和)

    做了一段时间的线性dp的题目是时候做一个总结 线性动态规划无非就是在一个数组上搞嘛, 首先看一个最简单的问题: 一,最长字段和 下面为状态转移方程 for(int i=2;i<=n;i++) { ...

  6. LIS LCS n^2和nlogn解法 以及LCIS

    首先介绍一下LIS和LCS的DP解法O(N^2) LCS:两个有序序列a和b,求他们公共子序列的最大长度 我们定义一个数组DP[i][j],表示的是a的前i项和b的前j项的最大公共子序列的长度,那么由 ...

  7. LIS和LCS LCIS

    首先介绍一下LIS和LCS的DP解法O(N^2) LCS:两个有序序列a和b,求他们公共子序列的最大长度 我们定义一个数组DP[i][j],表示的是a的前i项和b的前j项的最大公共子序列的长度,那么由 ...

  8. LIS,LCS,LICS 学习笔记

    1.最长上升子序列(LIS) 子序列: 1.可以不连续 2.相对位置不变 dp[i][j] 表示前i位置,最大值为j的LIS长度 1. dp[i-1][j] 前i-1位置,最大值为j的LIS长度 (没 ...

  9. dp入门(LIS,LCS)

    LCS

随机推荐

  1. Floyd算法 及其运用

    #include<stdio.h> ][]; ][]; void floyd(int n) { ;k<=n;k++) { ;i<=n;i++) { ;j<=n;j++) ...

  2. 【消息队列MQ】各类MQ比较

    目录(?)[-] RabbitMQ Redis ZeroMQ ActiveMQ JafkaKafka 目前业界有很多MQ产品,我们作如下对比: RabbitMQ 是使用Erlang编写的一个开源的消息 ...

  3. 关于Linux下进程间使用共享内存和信号量通信的时的编译问题

    今天在编译一个使用信号量实现进程同步时,出现了库函数不存在的问题.如下图 编译结果实际上是说,没include相应的头文件,或是头文件不存在(即系统不支持该库函数) 但我man shm_open是可以 ...

  4. auto_ptr浅析(转载)

    转载自http://www.cnblogs.com/qytan36/archive/2010/06/28/1766555.html auto_ptr是C++标准库中(<utility>)为 ...

  5. iOS 基于UIWebView的应用特点

    现在有许多ios应用都是基于UIWebView的应用,比如phonegap做出的那些程序.最近我也接触到了一个类似的程序,今天在这里分享一下这类程序的特点. 用UIWebView来实现程序,自然少不了 ...

  6. Linux下安装firefox最新版

    Linux刚安装好的时候,默认是火狐浏览器并且版本比较低,我的系统是CentOS,火狐版本号才31,用yum安装的话版本也不是最新,只要从官方网站下载最新版安装就可以了,方法如下: 首先去火狐主页,中 ...

  7. Java for LeetCode 056 Merge Intervals

    Given a collection of intervals, merge all overlapping intervals. For example, Given [1,3],[2,6],[8, ...

  8. DP:Skiing(POJ 1088)

     北大教你怎么滑雪 题目是中文的,要读懂题目其实不难 其实这道题挺经典的,我们这样想,他最终要找到一个最大值,这个时候我们就想到要用动态规划 那怎么用呢?我们同时这样想,由于滑雪的最高点我们不能立马找 ...

  9. GLSL的qualifier

    uniform:从应用程序到vertex shader 到fragment shader都能使用,但是值一直不变: varying:从vertex shader到fragment shader,在fr ...

  10. 好玩儿的expect

    前言 1> 借鉴里面的应用思想,使用断言提高代码的健壮性及维护性 2> 实现方式——不采用直接嵌入expect的方式,统一进行重写(提取常用断言方法,重新构造API) 官网介绍 https ...