CDOJ 1321 区间DP 解题报告

来源:互联网 发布:mac充电在哪 编辑:程序博客网 时间:2024/05/21 06:51

括号匹配 (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 longint 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;}