其实我正在尝试解决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;
}
答案 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;
}
}
我可能在某个地方有一个错误,我没有花时间检查,但我确认它适用于所有样本输入。