ZJU 2604 Little Brackets - 动态规划 Catalan数变形

题目描述:

定义一个括号序列的Depth为最深的嵌套层数。问n对括号,depth为k的括号序列共有多少种。

分析:

很类似Catalan数的题目。回忆经典的Catalan数:f[n]表示n对括号能够组成多少种不同的序列。那么可以得出f[n]的递推式:

f[n]=∑f[i]*f[n-i-1](0<=i<n)

对于此题可以用类似的思路得到递推式。

设f[i][j]表示i对括号能组成多少个depth为j的的序列。那么初始条件为f[0][0]=f[1][1]=1。考虑f[i][j],设与第一个前括号配对的后括号之间有k对括号(如下图),那么可以把f[i][j]分为两个子问题:括号里的k对括号,和括号后面的i-k-1对括号。

 ( ..[k对括号].. ) ..[i-k-1对括号]..

那么可以写出以下递推式:

f[i][j] = ∑ ( f[k][j-1]*g[i-k-1][j-1] + g[k][j-1]*f[i-k-1][j] ) ,(0<=k<i),其中g[i][j]=∑f[i][k](0<=k<=j)。

显然最后数字很大,需要大数

  1. /*
  2. ZJU2604 Little Brackets
  3. */
  4. #include <stdio.h>
  5. #include <string.h>
  6. #define clr(a) memset(a,0,sizeof(a))
  7. #define cpy(a,b) memcpy(a,b,sizeof(b))
  8. #define N 51
  9. /****************************************************/
  10. #define DIGIT 4 //一个数组元素存放的位数个数
  11. #define DEPTH 10000 //DEPTH = 10DIGIT
  12. #define MAX 500 //数组的长度
  13. typedef int bignum_t[MAX+1];
  14. //赋值
  15. void value(bignum_t a,const char val[]){    //val为数字字符串 
  16.     char buf[MAX*DIGIT+1],ch;
  17.     int i,j;
  18.     memset((void*)a,0,sizeof(bignum_t));
  19.     memcpy(buf,val,sizeof(val));
  20.     
  21.     for (a[0]=strlen(buf),i=a[0]/2-1;i>=0;i--)
  22.         ch=buf[i],buf[i]=buf[a[0]-1-i],buf[a[0]-1-i]=ch;
  23.     for (a[0]=(a[0]+DIGIT-1)/DIGIT,j=strlen(buf);j<a[0]*DIGIT;buf[j++]='0');
  24.     for (i=1;i<=a[0];i++)
  25.     for (a[i]=0,j=0;j<DIGIT;j++)
  26.         a[i]=a[i]*10+buf[i*DIGIT-1-j]-'0';
  27.     for (;!a[a[0]]&&a[0]>1;a[0]--);
  28. }
  29. //输出
  30. void Write(const bignum_t a){
  31.     int i,j;
  32.     for (printf("%d",a[i=a[0]]),i--;i;i--)
  33.     for (j=DEPTH/10;j;j/=10)
  34.         printf("%d",a[i]/j%10);
  35.     puts("");
  36. }
  37. //加法
  38. void add(bignum_t a,const bignum_t b){//高精度数a+b,结果在a中
  39.     int i;
  40.     for (i=1;i<=b[0];i++)
  41.     if ((a[i]+=b[i])>=DEPTH) a[i]-=DEPTH,a[i+1]++;
  42.     if (b[0]>=a[0]) a[0]=b[0];
  43.     else
  44.     for (;a[i]>=DEPTH&&i<a[0];a[i]-=DEPTH,i++,a[i]++);
  45.     a[0]+=(a[a[0]+1]>0);
  46. }
  47. //大数乘大数 
  48. void mul(bignum_t c,const bignum_t a,const bignum_t b){//高精度数a*b,结果在c中
  49.     int i,j;
  50.     memset((void*)c,0,sizeof(bignum_t));
  51.     for (c[0]=a[0]+b[0]-1,i=1;i<=a[0];i++)
  52.     for (j=1;j<=b[0];j++)
  53.     if ((c[i+j-1]+=a[i]*b[j])>=DEPTH)
  54.     c[i+j]+=c[i+j-1]/DEPTH,c[i+j-1]%=DEPTH;
  55.     for (c[0]+=(c[c[0]+1]>0);!c[c[0]]&&c[0]>1;c[0]--);
  56. }
  57. /**************************************************/
  58. bignum_t f[N][N];
  59. bignum_t g[N][N];
  60. bignum_t x,y;
  61. #define G(a,b) ((a)<(b)?(g[a][a]):(g[a][b]))
  62. int main()
  63. {
  64.     int i,j,k,n,m,T=0;
  65.     for(i=0;i<N;i++) for(j=0;j<N;j++){
  66.         value(f[i][j],"0"); value(g[i][j],"0");
  67.     }
  68.     //DP
  69.     value(f[0][0],"1"); value(f[1][1],"1");
  70.     value(g[0][0],"1"); value(g[1][1],"1");
  71.     for(i=2;i<N;i++) for(j=1;j<=i;j++){
  72.         for(k=0;k<i;k++){
  73.             mul(x,f[k][j-1],G(i-k-1,j-1));
  74.             mul(y,G(k,j-1),f[i-k-1][j]);
  75.             add(x,y);
  76.             add(f[i][j],x);
  77.         }
  78.         cpy(g[i][j],g[i][j-1]);
  79.         add(g[i][j],f[i][j]);
  80.     }
  81.     
  82.     //input
  83.     while(scanf("%d%d",&n,&m),n+m){
  84.         if(T) puts("");
  85.         printf("Case %d: ",++T);
  86.         Write(f[n][m]);
  87.     }
  88.     
  89.     return 0;
  90. }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值