简体   繁体   English

如何在以下C ++代码中进行记忆

[英]How to do memoisation in following c++ code

Actually i am trying to solve SPOJ Problem: [SPOJ] http://www.spoj.com/problems/SQRBR/ . 实际上,我正在尝试解决SPOJ问题:[SPOJ] http://www.spoj.com/problems/SQRBR/ I came up with recurence to solve it but i am not getting how to do memoisation. 我想出了递归来解决它,但我没有做记忆的方法。 Any suggestion on how to memoisation for given problem will be helpful. 关于如何为给定问题记忆的任何建议都将有所帮助。 my code is giving correct answer , but it is giving TLE in spoj Here my code : 我的代码给出了正确的答案,但是它在spoj中给出了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;
} 

I can think of one relatively simple and possibly significant optimization. 我可以想到一个相对简单且可能重要的优化。

First, instead of making the "counter" a reference, make it the return value of the function. 首先,不要使“计数器”成为引用,而应使其成为函数的返回值。 Hear me out for a bit here. 在这里让我听见一点。

Now say the positions you're given are "1, 7, 15". 现在说您得到的职位是“ 1、7、15”。 Instead of recursively going "1, 2, 3, 4, 5, 6, 7", you can be a little tricky and go to 7 in one step. 与其递归地执行“ 1、2、3、4、5、6、7”,您可能会有些棘手,一步就达到7。

You just need to count the number of permutations which can be used to go between 1 and 7, for every possible number of opening parens (in this case, 3, 4, 5 and 6) 您只需要为每个可能的打开括号数(在这种情况下为3、4、5和6)计算可以用于1到7之间的排列数。

For example, how many ways exist to have 3 opening parens between 1 and 7? 例如,有多少种方法可以在1至7之间设置3个开放括号?

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

5 permutations (unless I missed one). 5个排列(除非我错过了一个)。 So you can add 5*balancedParen(n, open+3, position+6, close+3, str, s, counter) to your result. 因此,您可以将5*balancedParen(n, open+3, position+6, close+3, str, s, counter)到结果中。 And do a similar thing for 4, 5, and 6 opening parens. 并对4、5和6开头的括号执行类似的操作。

Of course you'd need to write another function (recursive approach seems simplest) to find that number "5". 当然,您需要编写另一个函数(递归方法似乎最简单)才能找到数字“ 5”。 But the advantage is that the total number of function calls is now (calls to get from 1 to 7) + (calls to get from 7 to 15) , rather than (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) (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) ,而不是(calls to get from 1 to 7) * (calls to get from 7 to 15)

Here is some code which should work using the algorithm I described: 这是一些应该使用我描述的算法工作的代码:

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;
    }
}

I may have a bug somewhere, I didn't really spend the time to check, but I verified it works for all the sample input. 我可能在某个地方有一个错误,我并没有花时间检查,但是我验证了它适用于所有示例输入。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM