所涉及的递归调用到底发生了啥?
Posted
技术标签:
【中文标题】所涉及的递归调用到底发生了啥?【英文标题】:What exactly is happening in the recursive calls involved?所涉及的递归调用到底发生了什么? 【发布时间】:2015-11-06 12:10:35 【问题描述】:所以,我试图解决以下问题:http://www.spoj.com/problems/MREPLBRC/en/
正则括号序列是一串仅由左括号和右括号组成的字符串,并且满足以下条件:
• 空字符串是常规括号序列。
• 如果 A 是正则括号 0 序列,则 (A)、[A] 和 A 也是正则括号序列。
• 如果 A 和 B 是正则括号序列,则 AB 也是正则括号序列。
例如,序列 [()]、 i [] 是正则序列,但序列 [(([, 和 [])([]不是。
Ivica 找到了一个看起来可能是常规括号序列的字符串。一些字符已经被弄脏并且难以辨认,并且可能是任何字符。
编写一个程序,计算字符串中难以辨认的字符有多少种方式可以被括号替换,从而得到一个规则的括号序列。这个数字可能很大,所以只输出它的最后 5 位。
输入
第一行包含一个偶数 N (2
第二行包含字符串。难以辨认的字符由“?”表示字符。
输出
输出字符串可以读取的常规括号序列的数量。
经过深思熟虑,我无法真正为此形成解决方案,因此我试图寻找解决方案。我在这里找到它:http://ruhinraihan.blogspot.in/2012/08/spoj-4038-counting-way-of-bracket.html
下面是代码:
#include<iostream>
#include<list>
#include<string>
#include<cstring>
#include<sstream>
#include<cctype>
#include<string.h>
#include<algorithm>
#include<cmath>
#include<stack>
#include<fstream>
#include<cstdlib>
#include<vector>
#include<map>
#include<utility>
#include<iomanip>
#include<queue>
using namespace std;
#define INF (1<<29)
#define SET(a) memset(a,-1,sizeof(a))
#define ALL(a) a.begin(),a.end()
#define CLR(a) memset(a,0,sizeof(a))
#define FILL(a,v) memset(a,v,sizeof(a))
#define PB push_back
#define FOR(i,n) for(int i = 0;i<n;i++)
#define PI acos(-1.0)
#define EPS 1e-9
#define MP(a,b) make_pair(a,b)
#define READ(f) freopen(f, "r", stdin)
#define WRITE(f) freopen(f, "w", stdout)
#define LL long long
#define MOD 100000
bool moduloUsed;
LL memo[200+10][200+10];
string s;
LL func(int left, int right)
int i, valid;
if(left>right) return 1;
if(memo[left][right]!=-1) return memo[left][right];
LL ret=0;
for(i=left+1;i<=right;i+=2)
if(s[left]=='(' && s[i]==')') valid=1;
else if(s[left]=='' && s[i]=='') valid=1;
else if(s[left]=='[' && s[i]==']') valid=1;
else if(s[left]=='?' && s[i]==')') valid=1;
else if(s[left]=='?' && s[i]=='') valid=1;
else if(s[left]=='?' && s[i]==']') valid=1;
else if(s[left]=='(' && s[i]=='?') valid=1;
else if(s[left]=='' && s[i]=='?') valid=1;
else if(s[left]=='[' && s[i]=='?') valid=1;
else if(s[left]=='?' && s[i]=='?') valid=3;
else valid=0;
ret+=valid*func(left+1,i-1)*func(i+1,right);
if(ret>MOD)
moduloUsed=true;
ret%=MOD;
return memo[left][right]=ret;
int main()
LL ans,length;
while(cin>>length>>s)
SET(memo);
ans=func(0,length-1);
if(!moduloUsed)
cout<<ans<<endl;
else
printf("%05lld\n",ans);
return 0;
我想知道,函数fun
中到底发生了什么。我知道它正在遍历输入字符串,并检查平衡括号条件的可能组合,但是,func(left+1,i-1)*func(i+1,right)
,这两个递归调用代表什么?请帮我。
【问题讨论】:
但是您是否也知道在 C 和 C++ 中有 switch/case 语句? @decltype_auto,你为什么在这里询问开关/案例?可以用另一种方式重写这段代码(使用switch
),但这无助于Harry 理解这段代码的逻辑。
@decltype_auto,无意冒犯,但如果您停止向其他人炫耀您的知识渊博并帮助我,这对我会有很大帮助。正是因为像你这样的人,很多初学者常常因为你试图表现出你惊人的幽默而无法学习,相信我,这根本没有那么神奇。
@decltype_auto,我愿意,但是,与其说对任何人都没有帮助的话,不如让你的答案(这有助于 OP)说出我的感受。不要说它会提高可读性,而是写一个答案来表明它会提高可读性。如果是这样,我很乐意接受您的回答。
@decltype_auto,天哪。这太神奇了。您自己建议代码需要重组,现在您自己说 SO 不是代码编写服务。至少看看我问的问题。我从来没有要求你为我写代码。我只是请你帮我解释一下逻辑。至少在一件事上保持头脑清醒。
【参考方案1】:
基本上,答案是通过将任何开括号对的所有有效组合相乘来得出的。冗长的 if 语句是递归函数的停止条件,因为任何对都可以有 0,1 或 3 个有效组合。让你失望的递归调用实际上是(结合 for 循环)扫描整个字符串以查找括号对。如果说字符串是对称的,那将是一个更简单的调用:fun(left + 1, right -1)
【讨论】:
func(left+1,i-1)具体代表什么?我认为 func(i+1,right) 基本上意味着,我们正在为下一个位置做这件事。另外,为什么我们将 i 增加 2 个单位?为什么不只有 1 个?func(left+1, i-1)
是从左边开始的子串,另一个是从右边结束的子串。它们仅在整个字符串中重叠
实际上,我认为更好的措辞是 that one Treats ? chars 作为左括号,另一个作为右括号。希望我没有记错。以上是关于所涉及的递归调用到底发生了啥?的主要内容,如果未能解决你的问题,请参考以下文章