括号匹配 (parenthesis.pas/cpp/c)
【题目描述】
给出长度为N的括号序列(只包含(,),[,]),问有多少种方法删掉这些括号的一个子集,使得剩下的括号序列是合法的,请注意不能全部删完。
【输入格式】
输入的第一行是一个整数N,表示序列的长度。
接下来一行N个字符,表示括号序列。
【输出格式】
一行,表示方案数模1000000007的结果。
【样例输入】
4
()[]
【样例输出】
3
【数据范围】
30%的数据保证:1 <= N <= 20。
100%的数据保证:1 <= N <= 300。
【解题报告】
考虑用动态规划来统计方案数。
不妨有dp(l,r)表示只考虑(l,r)区间的括号序列,最终合法的方案数(允许删空)
转移显然只有两种决策,第l个括号不进行匹配(删除),转移到dp(l+1,r),和第l个括号进行匹配,
直接进行暴力枚举匹配即可。
复杂度O(n3)
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 310
#define mod 1000000007
#define LL long long
int n;
char s[N];
LL dp[N][N];
bool match(int l,int r)
{
return (s[l]=='('&&s[r]==')')||(s[l]=='['&&s[r]==']');
}
LL dfs(int l,int r)
{
if(~dp[l][r]) return dp[l][r];
LL &ans=dp[l][r]=0;
if(l>=r) return ans=1;
ans=dfs(l+1,r)%mod;
for(int i=l+1;i<=r;i++)
{
if(match(l,i))
{
ans+=dfs(l+1,i-1)*dfs(i+1,r);
ans%=mod;
}
}
return ans%mod;
}
int main()
{
freopen("parenthesis.in","r",stdin);
freopen("parenthesis.out","w",stdout);
scanf("%d%s",&n,s);
memset(dp,-1,sizeof(dp));
printf("%I64d",(dfs(0,n-1)-1)%mod);
return 0;
}