如何优化我的Langford序列函数?

时间:2015-09-25 01:39:38

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

这是我用一组数字对(112233 - > 312132)制作Langford序列的代码。我想写一个递归函数,因为我无法在任何地方找到一个在线作为算法的自我改进练习。我的问题是,我该如何优化它?有没有办法将动态编程应用于此并且具有更好的时间/空间复杂性,并强调时间复杂度?我当前的运行时复杂度是O(n ^ 2)和O(n)的空间复杂度。编写清洁代码的任何帮助也值得赞赏。谢谢。另外,这是P还是NP问题?

#include <iostream>
using namespace std;

const int arrLen = 8;
const int seqLen = 8;

bool langfordSequence(int * arr, int indx, int *seq, int pos);
int main() {

    int arr[] = {1,1,2,2,3,3,4,4};
    int seq[] = {0,0,0,0,0,0,0,0};

    bool test = langfordSequence(arr, 0, seq, 0);

    if (test)
        cout << "Langford Sequence Successful: " << endl;
    else
        cout << "Langford Sequence Failed: " << endl;

    for (int i = 0; i < seqLen; i++)
    {
        cout << seq[i] << " ";
    }   
    return 0;
}

bool langfordSequence(int * arr, int indx, int *seq, int pos)
{

    if (indx >= arrLen - 1) //this means we've reached the end of the array
        return true;

    if (pos + arr[indx] + 1 >= seqLen)  //if the second part of the number is off the array
        return false;

    if (seq[pos] == 0 && seq[pos + arr[indx] + 1] == 0)
    {
        seq[pos] = arr[indx];
        seq[pos + arr[indx] + 1] = arr[indx];
        if (langfordSequence(arr, indx + 2, seq, 0))    //the current pair is good, go to the next one, start from the beginning
            return true;
        else
        {
            seq[pos] = 0;
            seq[pos + arr[indx] + 1] = 0;
            if (langfordSequence(arr, indx, seq, pos + 1))
                return true;
        }
    }
    else
    {
        if (langfordSequence(arr, indx, seq, pos + 1))  //current position is no good, try next position
            return true;
    }
}

1 个答案:

答案 0 :(得分:0)

这是我在评论中提到的想法的伪代码。我还没有去寻找其他人做过这样的事情(因为我喜欢先自己解决问题),但其他人可能有优先权。

算法LANGFORD 参数N(顶级,最终序列中的最大元素),M(中间的最大元素,钩子序列)。在顶层,M = N. 返回:所有长度为2N的序列的列表,使得1..M中的每个元素j恰好两次由正好j个元素分开,并且第二个M的位置小于N + M / 2 + 1.所有其他元素序列设置为0。

If M == 1 (base case)
  Let S' := []
  For i := 0 to N-2
    Let s' be the length 2N sequence containing the subsequence "101" starting at position i (counting from 0), and zero everywhere else.
    Insert s' into S'
  Return S'

Otherwise: (inductive case)
Let S' := []
Let S := LANGFORD(N,M-1)
For each s in S
  Let r := reverse(s)
  For i := 0 to floor(N - M/2 + 1)
    If s[i] == s[i+M+1] == 0
      Let s' be s with s'[i] and s'[i+M+1] replaced by M
      Insert s' into S'
    If r != s and r[i] == r[i+M+1] == 0
      Let r' be r with r'[i] and r'[i+M+1] replaced by M
      Insert r' into S'
Return S'

对于N = 4运行该算法,我们最初M = 4并且递归直到N = 4,M = 1.该步骤给出了列表[[10100000],[01010000],[00101000]]。我们将其传递回M = 2步骤,其找到钩住序列[[12102000],[10120020],[20020101],[02002101],[00201210],[01210200],[20021010],[00201210], [20121000],[02012100]。将这些传递到M = 3步骤,得到[[30023121],[13120320],[13102302],[31213200],[23021310],[23121300],[03121320]]。最后,我们返回顶层函数并找到序列[[41312432]],它也代表了它的对称双23421314。

基本上,我们正在尝试将每个拼图块(如“30003”)放入每个可能的解决方案中,请记住任何解决方案的镜像都是一种解决方案。时间和空间的复杂性主要受到N / 2周围M值的潜在解的组合爆炸的支配。将序列存储为字节数组以使用向量指令,将列表存储为数组列表(C ++中的向量,Haskell中的[sequence]等)可能会很快。