longest common subsequence introduction to algorithm 3rd, example 15.4

算法导论 第三版 15.4动态规划问题

升级到vs2012 update1, 结果仍然没有C++11的初始化列表功能, 测试函数里面给vector添加data就比较丑了。


//longest common subsequence introduction to algorithm 3rd, example 15.3


#include <iostream>
#include <vector>
#include <algorithm>
#include <cassert>
#include <ostream>
#include <iterator>
#include <limits>
#include <complex>
#include "stopwatch.h"

struct Record
{
    enum Direction
    {
        eUnknown = 0,
        eMatch,
        eMoveV1,
        eMoveV2,
    };

    Record () : max(std::numeric_limits<size_t>::max()), direction(eUnknown) {}
    // I get bug here, to avoid it, use explicit type conversion
    operator bool() {return max != std::numeric_limits<rsize_t>::max();}

    size_t    max;
    Direction direction;
};

template <typename value_t>
size_t compute_lcs(const std::vector<value_t> & v1, size_t pv1, const std::vector<value_t> & v2, size_t pv2, std::vector<std::vector<Record>> & solution)
{
    if (solution[pv1][pv2])
    {
        return solution[pv1][pv2].max;
    }

    size_t max = 0;
    if (v1[pv1] == v2[pv2])
    {
        max = 1 + ((pv1 && pv2) ? compute_lcs(v1, pv1-1, v2, pv2-1, solution) : 0);
        solution[pv1][pv2].max = max;
        solution[pv1][pv2].direction = Record::eMatch;
    }
    else
    {
        auto v1max = pv2 ? compute_lcs(v1, pv1,   v2, pv2-1, solution) : 0;
        auto v2max = pv1 ? compute_lcs(v1, pv1-1, v2, pv2  , solution) : 0;
        max = std::max(v1max, v2max);
        solution[pv1][pv2].max = max;
        solution[pv1][pv2].direction = v1max > v2max ? Record::eMoveV2 : Record::eMoveV1;
    }
    return max;
}

template <typename value_t>
size_t compute_lcs_none_recursive(const std::vector<value_t> & v1, const std::vector<value_t> & v2, std::vector<std::vector<Record>> & solution)
{
    for (size_t iv1 = 0; iv1 < v1.size(); ++iv1)
    {
        for (size_t iv2 = 0; iv2 < v2.size(); ++iv2)
        {
            if (v1[iv1] == v2[iv2])
            {
                solution[iv1][iv2].max = iv1 && iv2 ? solution[iv1-1][iv2-1].max + 1 : 1;
                solution[iv1][iv2].direction = Record::eMatch;
            }
            else
            {
                auto v1max = iv2 ? solution[iv1][iv2-1].max : 0;
                auto v2max = iv1 ? solution[iv1-1][iv2].max : 0;
                solution[iv1][iv2].max = std::max(v1max, v2max);
                solution[iv1][iv2].direction = v1max > v2max ? Record::eMoveV2 : Record::eMoveV1;
            }
        }
    }
    return solution[v1.size()-1][v2.size()-1].max;
}

template <typename value_t>
void print_solution(const std::vector<value_t> & v1, const std::vector<std::vector<Record>> & solution, size_t p1, size_t p2)
{
    switch (solution[p1][p2].direction)
    {
    default:
        assert(false && "unexpected");
    case Record::eUnknown:
        break;
    case Record::eMatch:
        if (p1 && p2)
        {
            print_solution(v1, solution, p1-1, p2-1);
        }
        std::cout << v1[p1];
        break;
    case Record::eMoveV1:
        if (p1)
        {
            print_solution(v1, solution, p1-1, p2);
        }
        break;
    case Record::eMoveV2:
        if (p2)
        {
            print_solution(v1, solution, p1, p2-1);
        }
        break;
    }
}

template <typename value_t>
void compute_lcs(const std::vector<value_t> & v1, const std::vector<value_t> & v2)
{
    std::vector<std::vector<Record>> solution(v1.size());
    for (auto & i : solution)
    {
        i.resize(v2.size());
    }


    Stopwatch watch;
    watch.start();
    auto max_len = compute_lcs(v1, v1.size()-1, v2, v2.size()-1, solution);
    watch.stop();
    std::cout << "find the longest subsequence length " << max_len << " use time " << watch.elapsed() << " ms" << std::endl;
    std::cout << "the solution is :\n";
    print_solution(v1, solution, v1.size()-1, v2.size()-1);
}

template <typename value_t>
void compute_lcs_none_recursive(const std::vector<value_t> & v1, const std::vector<value_t> & v2)
{
    std::vector<std::vector<Record>> solution(v1.size());
    for (auto & i : solution)
    {
        i.resize(v2.size());
        i[0].max = 0;
    }
    for (auto & i : solution[0])
    {
        i.max = 0;
    }

    Stopwatch watch;
    watch.start();
    auto max_len = compute_lcs_none_recursive(v1, v2, solution);
    watch.stop();
    std::cout << "none recursive find the longest subsequence length " << max_len << " use time " << watch.elapsed() << " ms" << std::endl;
    std::cout << "the solution is :\n";
    print_solution(v1, solution, v1.size()-1, v2.size()-1);
}

void test1()
{
    std::vector<char> v1;
    v1.reserve(7);
    v1.push_back('A');
    v1.push_back('B');
    v1.push_back('C');
    v1.push_back('B');
    v1.push_back('D');
    v1.push_back('A');
    v1.push_back('B');
    std::vector<char> v2;
    v2.reserve(6);
    v2.push_back('B');
    v2.push_back('D');
    v2.push_back('C');
    v2.push_back('A');
    v2.push_back('B');
    v2.push_back('A');

    std::cout << "test 1 : ";
    std::copy(v1.begin(), v1.end(), std::ostream_iterator<char>(std::cout, ""));
    std::cout << "  and  ";
    std::copy(v2.begin(), v2.end(), std::ostream_iterator<char>(std::cout, ""));
    std::cout << "\nthe expected answer is :\nBCBA" << std::endl;

    compute_lcs(v1, v2);
    std::cout << std::endl;
    compute_lcs_none_recursive(v1, v2);
    std::cout << std::endl;
}


void test2()
{
    std::vector<char> v1;
    v1.reserve(29);
    // ACCG GTCG AGTG CGCG GAAG CCGG CCGAA
    v1.push_back('A');
    v1.push_back('C');
    v1.push_back('C');
    v1.push_back('G');

    v1.push_back('G');
    v1.push_back('T');
    v1.push_back('C');
    v1.push_back('G');

    v1.push_back('A');
    v1.push_back('G');
    v1.push_back('T');
    v1.push_back('G');


    v1.push_back('C');
    v1.push_back('G');
    v1.push_back('C');
    v1.push_back('G');

    v1.push_back('G');
    v1.push_back('A');
    v1.push_back('A');
    v1.push_back('G');

    v1.push_back('C');
    v1.push_back('C');
    v1.push_back('G');
    v1.push_back('G');

    v1.push_back('C');
    v1.push_back('C');
    v1.push_back('G');
    v1.push_back('A');
    v1.push_back('A');

    std::vector<char> v2;
    v2.reserve(28);
    // GTCG TTCG GAAT GCCG TTGC TCTG TAAA
    v2.push_back('G');
    v2.push_back('T');
    v2.push_back('C');
    v2.push_back('G');

    v2.push_back('T');
    v2.push_back('T');
    v2.push_back('C');
    v2.push_back('G');

    v2.push_back('G');
    v2.push_back('A');
    v2.push_back('A');
    v2.push_back('T');

    v2.push_back('G');
    v2.push_back('C');
    v2.push_back('C');
    v2.push_back('G');

    v2.push_back('T');
    v2.push_back('T');
    v2.push_back('G');
    v2.push_back('C');

    v2.push_back('T');
    v2.push_back('C');
    v2.push_back('T');
    v2.push_back('G');

    v2.push_back('T');
    v2.push_back('A');
    v2.push_back('A');
    v2.push_back('A');

    std::cout << "test 2 : ";
    std::copy(v1.begin(), v1.end(), std::ostream_iterator<char>(std::cout, ""));
    std::cout << "  and  ";
    std::copy(v2.begin(), v2.end(), std::ostream_iterator<char>(std::cout, ""));
    std::cout << "\nthe expected answer is :\nGTCGTCGGAAGCCGGCCGAA" << std::endl;

    compute_lcs(v1, v2);
    std::cout << std::endl;
    compute_lcs_none_recursive(v1, v2);
    std::cout << std::endl;
}

class Value
{
public:
    Value(int a) : mValue(a) {}
    bool operator==(const Value & r) const {return mValue == r.mValue;}

private:
    friend std::ostream & operator<<(std::ostream & os, const Value & value);
    int mValue;
};

std::ostream & operator<<(std::ostream & os, const Value & value)
{
    os << value.mValue;
    return os;
}

void test3()
{
    std::vector<Value> v1;
    v1.reserve(7);
    v1.push_back(1);
    v1.push_back(2);
    v1.push_back(3);
    v1.push_back(2);
    v1.push_back(4);
    v1.push_back(1);
    v1.push_back(2);
    std::vector<Value> v2;
    v2.reserve(6);
    v2.push_back(2);
    v2.push_back(4);
    v2.push_back(3);
    v2.push_back(1);
    v2.push_back(2);
    v2.push_back(1);

    std::cout << "test 3 : ";
    std::copy(v1.begin(), v1.end(), std::ostream_iterator<Value>(std::cout, ""));
    std::cout << "  and  ";
    std::copy(v2.begin(), v2.end(), std::ostream_iterator<Value>(std::cout, ""));
    std::cout << "\nthe expected answer is :\nBCBA" << std::endl;

    compute_lcs(v1, v2);
    std::cout << std::endl;
    compute_lcs_none_recursive(v1, v2);
    std::cout << std::endl;
}

int main()
{
    std::cout << "start" << std::endl;
    test1();
    std::cout << std::endl;
    test2();
    std::cout << std::endl;
    test3();

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 最长公共子序列(Longest Common Subsequence)指的是在两个序列中找到最长的公共子序列,这个公共子序列可以不连续,但是需要保持相对顺序不变。例如,对于序列ABCD和ACDFG,它们的最长公共子序列是ACD。 ### 回答2: 最长公共子序列(Longest Common Subsequence,简称LCS)是指在给定多个序列中,找到最长的一个子序列,该子序列同时出现在这些序列中,并且其他元素的相对顺序保持一致。 举个例子,假设有两个序列A和B,A为[1, 2, 3, 4, 5],B为[2, 4, 5, 6]。它们的一个最长公共子序列是[2, 4, 5],该子序列同时存在于A和B中。 求解LCS的问题可以用动态规划的方法来解决。我们可以构建一个二维数组dp,其中dp[i][j]表示序列A的前i个元素和序列B的前j个元素的LCS长度。那么dp[i][j]可以通过以下方式得到: 1. 如果A[i]等于B[j],则dp[i][j]等于dp[i-1][j-1] + 1; 2. 如果A[i]不等于B[j],则dp[i][j]等于max(dp[i-1][j], dp[i][j-1])。 通过填充整个dp数组,最终可以得到序列A和序列B的LCS长度。要找到具体的LCS序列,则可以通过反向遍历dp数组进行构建。 LCS问题在字符串处理、DNA序列匹配、版本控制等领域都有广泛的应用。其时间复杂度为O(m*n),其中m和n分别为序列A和序列B的长度。 ### 回答3: 最长公共子序列(Longest Common Subsequence)是一个经典的计算机科学问题。给定两个序列S和T,我们要找出它们之间最长的公共子序列。 子序列是从给定序列中按顺序选择几个元素而组成的序列。而公共子序列指的是同时是序列S和T的子序列的序列。 为了解决这个问题,可以使用动态规划的方法。我们可以定义一个二维数组dp,其中dp[i][j]表示序列S的前i个元素和序列T的前j个元素之间的最长公共子序列的长度。 接下来,我们可以使用以下递推关系来填充dp数组: 如果S[i]等于T[j],则dp[i][j] = dp[i-1][j-1] + 1; 如果S[i]不等于T[j],则dp[i][j] = max(dp[i-1][j], dp[i][j-1])。 最后,我们可以通过查看dp[S.length()][T.length()]来得到最长公共子序列的长度。 此外,我们也可以用回溯法来还原最长公共子序列本身。我们可以从dp[S.length()][T.length()]开始,如果S[i]等于T[j],则将S[i]添加到结果序列中,并向左上方移动,即i = i-1,j = j-1。如果S[i]不等于T[j],则根据dp数组的值选择向上(i = i-1)或向左(j = j-1)移动。 总之,最长公共子序列问题是一个经典的计算机科学问题,可以使用动态规划的方法解决。我们可以通过构建二维dp数组来计算最长公共子序列的长度,并可以使用回溯法来还原它本身。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值