2011.12.26 POJ1240

题目大意:一直一颗M叉树的先序遍历和后序遍历,求中序遍历的种数。(by the way,如果已知先序和中序,那么后序唯一,如果已知中序和后序,先序也是唯一的)

题目的关键在于“分治”的思想来DP,求得每个结点有多少个子节点,先把每个子节点的可能种数求出来,然后相乘,然后再乘以C(m,n),其中n为当前结点的子节点数目,所得到的结果就是以当前结点为根的中序遍历的种数。 顺便说一句,求C(m,n)的时候也可以用DP。



#include <iostream>
#include <cassert>
using namespace std;


int M;
char str1[27];
char str2[27];
int c[21][21];


int C(int m,int n)
{
assert( m<=20 );
assert( n<=m );
if( n == 0 || m == 0 || m == n )
return 1;


if( 2*n > m )
n = m-n;
if( c[m][n] != -1 )
return c[m][n];
else
{
c[m-1][n-1] = C( m-1, n-1 );
c[m-1][n] = C( m-1,n );
return c[m][n] = c[m-1][n-1] + c[m-1][n];
}
}


int Partition(const int beg1,const int end1,const int beg2,const int end2)  //针对str的beg到end来分析
{
if( beg1 == end1 )
return 1;
int subroot_pos = beg1 + 1;
char* psubroot_instr2_old = str2+beg2-1;


int ret = 1;
int subtree_nums = 0;
for(; subroot_pos<=end1;)
{
char subroot = str1[subroot_pos];
char* psubroot_instr2_new = strchr(str2,subroot);
int len = psubroot_instr2_new - psubroot_instr2_old;
assert( len != 0 );
//ret = ret*Partition(subroot_pos,subroot_pos+len-1,psubroot_instr2_old-str2,psubroot_instr2_new-str2);
ret = ret*Partition(subroot_pos,subroot_pos+len-1,psubroot_instr2_new-str2-len+1,psubroot_instr2_new-str2);
psubroot_instr2_old = psubroot_instr2_new;
subroot_pos += len;
++subtree_nums;
}
ret = ret * C(M,subtree_nums);
return ret;
}


int main()
{
//freopen("in.txt","r",stdin);
while( true ){
scanf("%d",&M);
if( M == 0 )
break;
scanf("%s",str1);
scanf("%s",str2);
//init c
for(int i=0; i<=M; ++i)
for(int j=0; j<i; ++j)
c[i][j] = -1;
int res = Partition(0,strlen(str1)-1,0,strlen(str2)-1);
printf("%d\n",res);
}
return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值