【问题标题】:Longest Common Increasing Subsequence Dynamic Programming最长公共递增子序列动态规划
【发布时间】:2016-05-02 12:39:54
【问题描述】:

我正在努力寻找最长常见递增子序列问题的解决方案。如果您不熟悉它,这里有一个链接。 LCIS

这个问题基本上可以归结为两个不同的问题。 “最长公共子序列”和“最长递增子序列”。这是最长公共子序列的递归解决方案:

LCS(S,n,T,m)
{
if (n==0 || m==0) return 0;
if (S[n] == T[m]) result = 1 + LCS(S,n-1,T,m-1); // no harm in matching up
else result = max( LCS(S,n-1,T,m), LCS(S,n,T,m-1) );
return result;
}

基于此以及找到here 的通用递归公式,我一直在尝试实现该算法,以便可以使用动态编程。

int lcis(int S[4], int n, int T[4], int m, int prev)
{
  int result;

  if (n == 0 || m  == 0)
    return 1;
  if (S[n] == T[m] && S[n] > S[prev]){
    result = myMax(1 + lcis(S, n-1, T, m-1, n), lcis(S, n-1, T, m, prev),
                    lcis(S, n, T, m-1, prev)) ;
  }
  else
    result = max(lcis(S,n-1,T,m, prev), lcis(S,n,T,m-1, prev));

  return result;
}

显然这并没有给出正确的解决方案。任何帮助,将不胜感激。

例如,如果我给它两个序列 {1, 2, 4, 5} 和 {12, 1, 2, 4} 我得到输出 2。这里正确的输出是 3,对于 sub序列 {1,2,4}

编辑:

根据下面的建议,这是一些修改后的代码。仍然不是 100% 正确。但更接近。注意我现在使用向量,但这不应该改变任何东西。

int lcis(vector<int> S, int n, vector<int> T, int m, int size)
{
  int result;

  if (n < 0 || m < 0)
    return 0;
  if (S[n] == T[m] && (n == size - 1 || S[n] < S[n + 1] )){
    result = myMax(1 + lcis(S, n - 1, T, m - 1, size), lcis(S, n - 1, T, m, size),
                    lcis(S, n, T, m - 1, size));
  }
  else
    result = max(lcis(S, n-1, T, m, size), lcis(S, n, T, m-1, size));

  return result;
}

【问题讨论】:

  • “显然这并没有给出正确的解决方案”。不,一点也不明显。您没有显示输入或预期的 vs 实际输出。如果您需要帮助,请不要指望我们会通过网络链接了解问题,然后尝试将其与您的算法相匹配,然后尝试找出您给出的输入。
  • 在某些情况下,例如启动或重启时,没有prev。
  • @paddy 我已经用示例输入和输出更新了我的帖子。

标签: c++ c algorithm recursion dynamic-programming


【解决方案1】:

请记住,您正在向后遍历数组。所以这个测试

 S[n] > S[prev]

应该反过来:

 S[n] < S[prev]

我不知道你为什么需要 prev,因为它应该总是 n+1,所以也许使用

if (S[n] == T[m] && n < 3 && S[n] < S[n+1])

如果你需要让它适用于任何尺寸,那么要么传递尺寸,要么只是一个标志说不要检查 n+1

编辑:

我的错误 - 你想在n == 3(或大小)时经历第一个 if 情况,因为你正处于(可能)增加的子序列的开头。

if 测试应该是

if (S[n] == T[m] && (n == 3 || S[n] < S[n+1]))

注意这个 if 测试:

if (n == 0 || m  == 0)
    return 1;

忽略任一序列的第一个元素(并假设它位于递增子序列的末尾)。需要的是在任一序列开始之前停止递归。您还知道,当您在序列开始之前走时,您不可能在子序列中,因此您可以为子序列的长度返回 0。所以测试应该是

if (n < 0 || m < 0)
    return 0;

【讨论】:

  • 哇,你对 prev 变量说的太对了,我想多了。你的建议似乎奏效了。澄清一下,我会检查 n
  • 另一个考虑因素:如果序列大小不同,这个解决方案会起作用吗?
  • n
  • 嗯,你似乎是对的。经过测试,现在不管我给它哪两个序列,如果它们相同,则输出为两个。我仍然没有看到我的最终状况是如何导致这种情况的。你能澄清一下你的意思是你最终的尺寸+ 1吗?谢谢
  • 糟糕 - 我的意思是大小 - 1(即 3 表示两个序列都是 1、2、3、4)。我会用一些新信息更新我的答案。
猜你喜欢
  • 2017-04-26
  • 2016-08-12
  • 1970-01-01
  • 1970-01-01
  • 2011-02-07
  • 2016-04-11
  • 1970-01-01
  • 2012-10-25
  • 2019-05-28
相关资源
最近更新 更多