ZJU 2604 Little Brackets - 动态规划 Catalan数变形
2008-10-16 20:42
483 查看
题目描述:
定义一个括号序列的Depth为最深的嵌套层数。问n对括号,depth为k的括号序列共有多少种。
分析:
很类似Catalan数的题目。回忆经典的Catalan数:f
表示n对括号能够组成多少种不同的序列。那么可以得出f
的递推式:
f
=∑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)。
显然最后数字很大,需要大数。
/*
ZJU2604 Little Brackets
*/
#include <stdio.h>
#include <string.h>
#define clr(a) memset(a,0,sizeof(a))
#define cpy(a,b) memcpy(a,b,sizeof(b))
#define N 51
/****************************************************/
#define DIGIT 4 //一个数组元素存放的位数个数
#define DEPTH 10000 //DEPTH = 10DIGIT
#define MAX 500 //数组的长度
typedef int bignum_t[MAX+1];
//赋值
void value(bignum_t a,const char val[]){ //val为数字字符串
char buf[MAX*DIGIT+1],ch;
int i,j;
memset((void*)a,0,sizeof(bignum_t));
memcpy(buf,val,sizeof(val));
for (a[0]=strlen(buf),i=a[0]/2-1;i>=0;i--)
ch=buf[i],buf[i]=buf[a[0]-1-i],buf[a[0]-1-i]=ch;
for (a[0]=(a[0]+DIGIT-1)/DIGIT,j=strlen(buf);j<a[0]*DIGIT;buf[j++]='0');
for (i=1;i<=a[0];i++)
for (a[i]=0,j=0;j<DIGIT;j++)
a[i]=a[i]*10+buf[i*DIGIT-1-j]-'0';
for (;!a[a[0]]&&a[0]>1;a[0]--);
}
//输出
void Write(const bignum_t a){
int i,j;
for (printf("%d",a[i=a[0]]),i--;i;i--)
for (j=DEPTH/10;j;j/=10)
printf("%d",a[i]/j%10);
puts("");
}
//加法
void add(bignum_t a,const bignum_t b){//高精度数a+b,结果在a中
int i;
for (i=1;i<=b[0];i++)
if ((a[i]+=b[i])>=DEPTH) a[i]-=DEPTH,a[i+1]++;
if (b[0]>=a[0]) a[0]=b[0];
else
for (;a[i]>=DEPTH&&i<a[0];a[i]-=DEPTH,i++,a[i]++);
a[0]+=(a[a[0]+1]>0);
}
//大数乘大数
void mul(bignum_t c,const bignum_t a,const bignum_t b){//高精度数a*b,结果在c中
int i,j;
memset((void*)c,0,sizeof(bignum_t));
for (c[0]=a[0]+b[0]-1,i=1;i<=a[0];i++)
for (j=1;j<=b[0];j++)
if ((c[i+j-1]+=a[i]*b[j])>=DEPTH)
c[i+j]+=c[i+j-1]/DEPTH,c[i+j-1]%=DEPTH;
for (c[0]+=(c[c[0]+1]>0);!c[c[0]]&&c[0]>1;c[0]--);
}
/**************************************************/
bignum_t f
;
bignum_t g
;
bignum_t x,y;
#define G(a,b) ((a)<(b)?(g[a][a]):(g[a][b]))
int main()
{
int i,j,k,n,m,T=0;
for(i=0;i<N;i++) for(j=0;j<N;j++){
value(f[i][j],"0"); value(g[i][j],"0");
}
//DP
value(f[0][0],"1"); value(f[1][1],"1");
value(g[0][0],"1"); value(g[1][1],"1");
for(i=2;i<N;i++) for(j=1;j<=i;j++){
for(k=0;k<i;k++){
mul(x,f[k][j-1],G(i-k-1,j-1));
mul(y,G(k,j-1),f[i-k-1][j]);
add(x,y);
add(f[i][j],x);
}
cpy(g[i][j],g[i][j-1]);
add(g[i][j],f[i][j]);
}
//input
while(scanf("%d%d",&n,&m),n+m){
if(T) puts("");
printf("Case %d: ",++T);
Write(f
[m]);
}
return 0;
}
定义一个括号序列的Depth为最深的嵌套层数。问n对括号,depth为k的括号序列共有多少种。
分析:
很类似Catalan数的题目。回忆经典的Catalan数:f
表示n对括号能够组成多少种不同的序列。那么可以得出f
的递推式:
f
=∑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)。
显然最后数字很大,需要大数。
/*
ZJU2604 Little Brackets
*/
#include <stdio.h>
#include <string.h>
#define clr(a) memset(a,0,sizeof(a))
#define cpy(a,b) memcpy(a,b,sizeof(b))
#define N 51
/****************************************************/
#define DIGIT 4 //一个数组元素存放的位数个数
#define DEPTH 10000 //DEPTH = 10DIGIT
#define MAX 500 //数组的长度
typedef int bignum_t[MAX+1];
//赋值
void value(bignum_t a,const char val[]){ //val为数字字符串
char buf[MAX*DIGIT+1],ch;
int i,j;
memset((void*)a,0,sizeof(bignum_t));
memcpy(buf,val,sizeof(val));
for (a[0]=strlen(buf),i=a[0]/2-1;i>=0;i--)
ch=buf[i],buf[i]=buf[a[0]-1-i],buf[a[0]-1-i]=ch;
for (a[0]=(a[0]+DIGIT-1)/DIGIT,j=strlen(buf);j<a[0]*DIGIT;buf[j++]='0');
for (i=1;i<=a[0];i++)
for (a[i]=0,j=0;j<DIGIT;j++)
a[i]=a[i]*10+buf[i*DIGIT-1-j]-'0';
for (;!a[a[0]]&&a[0]>1;a[0]--);
}
//输出
void Write(const bignum_t a){
int i,j;
for (printf("%d",a[i=a[0]]),i--;i;i--)
for (j=DEPTH/10;j;j/=10)
printf("%d",a[i]/j%10);
puts("");
}
//加法
void add(bignum_t a,const bignum_t b){//高精度数a+b,结果在a中
int i;
for (i=1;i<=b[0];i++)
if ((a[i]+=b[i])>=DEPTH) a[i]-=DEPTH,a[i+1]++;
if (b[0]>=a[0]) a[0]=b[0];
else
for (;a[i]>=DEPTH&&i<a[0];a[i]-=DEPTH,i++,a[i]++);
a[0]+=(a[a[0]+1]>0);
}
//大数乘大数
void mul(bignum_t c,const bignum_t a,const bignum_t b){//高精度数a*b,结果在c中
int i,j;
memset((void*)c,0,sizeof(bignum_t));
for (c[0]=a[0]+b[0]-1,i=1;i<=a[0];i++)
for (j=1;j<=b[0];j++)
if ((c[i+j-1]+=a[i]*b[j])>=DEPTH)
c[i+j]+=c[i+j-1]/DEPTH,c[i+j-1]%=DEPTH;
for (c[0]+=(c[c[0]+1]>0);!c[c[0]]&&c[0]>1;c[0]--);
}
/**************************************************/
bignum_t f
;
bignum_t g
;
bignum_t x,y;
#define G(a,b) ((a)<(b)?(g[a][a]):(g[a][b]))
int main()
{
int i,j,k,n,m,T=0;
for(i=0;i<N;i++) for(j=0;j<N;j++){
value(f[i][j],"0"); value(g[i][j],"0");
}
//DP
value(f[0][0],"1"); value(f[1][1],"1");
value(g[0][0],"1"); value(g[1][1],"1");
for(i=2;i<N;i++) for(j=1;j<=i;j++){
for(k=0;k<i;k++){
mul(x,f[k][j-1],G(i-k-1,j-1));
mul(y,G(k,j-1),f[i-k-1][j]);
add(x,y);
add(f[i][j],x);
}
cpy(g[i][j],g[i][j-1]);
add(g[i][j],f[i][j]);
}
//input
while(scanf("%d%d",&n,&m),n+m){
if(T) puts("");
printf("Case %d: ",++T);
Write(f
[m]);
}
return 0;
}
相关文章推荐
- zoj 2604 Little Brackets(动态规划+递推+java)
- ZOJ 2604 Little Brackets DP
- ZOJ 2604 Little Brackets DP
- ZOJ 2604 Little Brackets(高精度+dp)
- 蓝桥杯_算法提高_金明的预算方案(动态规划、01背包变形)
- POJ-1157 LITTLE SHOP OF FLOWERS(动态规划)
- 【动态规划】【01背包变形】HDOJ 2037 今年暑假不AC
- 【原】 POJ 1157 LITTLE SHOP OF FLOWERS 动态规划 解题报告
- 【POJ1157】LITTLE SHOP OF FLOWERS (简单动态规划)
- bzoj4374 Little Elephant and Boxes【动态规划+折半搜索】
- <接上一篇> 动态规划一些变形 poj 1742 poj3046
- 一中OJ #1426 花店橱窗布置 [IOI1999 Day1T1 Little Shop of Flowers] | 动态规划 序列DP+递归路径 | 解题报告
- ZJU/ZOJ 1717 POJ 2030 The Secret Number 动态规划
- 动态规划训练10 [Coloring Brackets CodeForces - 149D]
- 动态规划(完全背包的变形)
- 约瑟夫问题变形 And Then There was One, LA 3882 递推 动态规划
- 【【henuacm2016级暑期训练】动态规划专题 M】Little Pony and Harmony Chest
- 【动态规划 变形】天堂 heaven.pas/c/cpp
- hdu 1069 Monkey and Banana 动态规划(最长递增子序列变形)
- 【动态规划】HDU1422重温世界杯【最大子段和变形】