如何在以下c ++代码中进行memoisation

时间:2013-05-22 18:37:17

标签: c++ dynamic-programming memoization

其实我正在尝试解决SPOJ问题:    [SPOJ] http://www.spoj.com/problems/SQRBR/。我想出了解决它的复原但我没有得到如何做回忆。关于如何对给定问题进行记忆的任何建议都会有所帮助。我的代码给出了正确的答案,但是它在给我们代码中的TLE:

#include <iostream>
#include <cstdio>

using namespace std;

void balancedParen(int n, int open, int position, int close, char str[], string s,    long long int &counter) {
if(close == n) {
    str[pos] = '\0';
    printf("%s\n", str);
    counter++;
    return;
}

if(s[position] == '(' ) {
  if(open <= n-1) {
    str[position] = '(';
    balancedParen(n, open+1, position+1, close, str, s, counter);
  }
} else {
  if(open < n) {
    str[position] = '(';
    balancedParen(n, open+1, position+1, close, str, s, counter);
  }
  if(open > close) {
    str[position] = ')';
    balancedParen(n, open, position+1, close+1, str, s, counter);
  }
}
    return ;
}

int main() {
      int a[100], n, k, i;
      long long counter = 0;
      int testCases;

      scanf("%d", &testCases);

      while(testCases--) {
              scanf("%d", &n);
              scanf("%d", &k);
              char str[100];
              string s = "..........................................................................";
      for(i = 0; i < k; i++) {
              scanf("%d", &a[i]);
              s[a[i]-1] = '(';
       }
      balancedParen(n, 0, 0, 0, str, s, counter);
      printf("%lld\n", counter);
      counter = 0;
   }
     return 0;
} 

1 个答案:

答案 0 :(得分:0)

我可以想到一个相对简单且可能重要的优化。

首先,不要将“counter”作为引用,而是将其作为函数的返回值。在这里听我说。

现在说你给的位置是“1,7,15”。而不是递归地“1,2,3,4,5,6,7”,你可能有点棘手,一步到7。

对于每个可能的开放数量(在这种情况下,3,4,5和6),您只需计算可用于1到7之间的排列数

例如,在1到7之间有3个开放的parens有多少种方式?

[[[]]]
[[][]]
[][][]
[[]][]
[][[]]

5个排列(除非我错过了一个)。因此,您可以在结果中添加5*balancedParen(n, open+3, position+6, close+3, str, s, counter)。并为4,5和6个开口做一个类似的事情。

当然,您需要编写另一个函数(递归方法似乎最简单)才能找到该数字“5”。但优点是函数调用的总数现在是(calls to get from 1 to 7) + (calls to get from 7 to 15),而不是(calls to get from 1 to 7) * (calls to get from 7 to 15)

以下是一些应该使用我所描述的算法的代码:

int countPermutations(int unclosed, int length, int toOpen)
{
    if (toOpen > length) // impossible to open this many, not enough length
        return 0;
    int toClose = length-toOpen;
    if (toClose - toOpen > unclosed)
        return 0; // No possibilities; not enough open parens to fill the length
    if (toOpen == 0 || toOpen == length)
        return 1; // Only one possibility now
    int ret = 0;
    if (toOpen > 0) // Count permutations if we opened a paren here
        ret += countPermutations(unclosed+1, length-1, toOpen-1); 
    if (unclosed > 0) // Count permutations if we closed a paren here
        ret += countPermutations(unclosed-1, length-1, toOpen); 
    return ret;
}

int countNLengthSolutions(int n, int unclosed, int position, int *positions, int remainingPositions)
{
    if (n % 2 != 0)
        return 0; // must be a length divisible by 2
    if (position > n)
        return 0;
    if (n-position < unclosed)
        return 0; // too many open parens, no way to complete within length

    if (remainingPositions == 0)
    {
        // Too many open parens to close by the time we get to length N?
        if ((n - position) < unclosed) 
            return 0;
        else // Say we have 4 open and a length of 10 to fill; we want (10-4)/2 = 3 more open parens.
            return countPermutations(unclosed, n-position, (n-position - unclosed)/2); 
    }
    else
    {
        int ret = 0;
        int toFill = *positions - position - 1;
        for (int openParens = 0; openParens <= toFill; openParens++)
        {
            int permutations = countPermutations(unclosed, toFill, openParens);
            if (permutations > 0)
                ret += permutations*countNLengthSolutions(n, unclosed+(2*openParens-toFill)+1, position+toFill+1, positions+1, remainingPositions-1);
        }
        return ret;
    }
}

我可能在某个地方有一个错误,我没有花时间检查,但我确认它适用于所有样本输入。