USACOTrainning.Cow Pedigrees

这题算是整死了,大大的Debug了一番。

大意是一个二叉树,点的度数只能为0或2,给出节点数和数的高度,问有多少种树,即树的计数问题。

用的是DP,f(i,j)表示i个节点构成j高度的树的个数,其中在转移的时候还需要small(i,j),表示i个节点的高度小于等于j的树的个数。

然后f(i,j)=f(left,j-1)*small(right,j-2)+small(left,j-2)*f(right,j-1)+f(left,j-1)*f(right,j-1)

 

  
    
1 #include < iostream >
2 #include < string >
3 #include < string .h >
4 #include < vector >
5 #include < math.h >
6 #include < time.h >
7   using namespace std;
8
9   const int M = 9901 ;
10
11   int small[ 205 ][ 105 ];
12   int s[ 205 ][ 105 ];
13   int no = 0 ;
14
15 // contruct a depth(<=k) tree with n nodes
16 int getSmall( int n, int k)
17 {
18 // if(n % 2 == 0) return 0;
19 int res = 0 ;
20 if (n == 1 && k >= 1 ) return 1 ;
21 if (n == 0 || k <= 0 ) return 0 ;
22 if (small[n][k] != - 1 ) return small[n][k];
23 for ( int i = 0 ; i <= n - 1 ; i ++ )
24 {
25 int left = i;
26 int right = n - 1 - i;
27 res += getSmall(left, k - 1 ) * getSmall(right, k - 1 );
28 res %= M;
29 }
30 small[n][k] = res;
31 return res;
32 }
33
34 int dfs( int n, int k)
35 {
36 // if(n % 2 == 0) return 0;
37 int res = 0 ;
38 if (n == 1 && k == 1 ) return 1 ;
39 if (n == 0 || k == 0 ) return 0 ;
40 if (s[n][k] != - 1 ) return s[n][k];
41 for ( int i = 0 ; i <= n - 1 ; i ++ )
42 {
43 int left = i;
44 int right = n - 1 - i;
45 int t = res;
46 res += dfs(left, k - 1 ) * getSmall(right, k - 2 );
47 res %= M;
48 res += dfs(right, k - 1 ) * getSmall(left, k - 2 );
49 res %= M;
50 res += dfs(left, k - 1 ) * dfs(right, k - 1 );
51 res %= M;
52 }
53 s[n][k] = res;
54 return res;
55 }
56
57 int main()
58 {
59 // freopen("nocows.in", "r", stdin);
60 // freopen("nocows.out", "w", stdout);
61
62 int n, k;
63 scanf( " %d%d " , & n, & k);
64 memset(small, - 1 , sizeof (small));
65 memset(s, - 1 , sizeof (s));
66 printf( " %d\n " , dfs(n, k));
67 }

 

到dp的转移方法和状态表示清楚后,其实就简单了,可是这里却出现了很悲剧的结果,花了很长的时间终于找出了原因。

getSmall函数中,原来是这样:

  
    
1 if (n == 1 && k >= 1 ) return 1 ;
2 if (n == 0 || k == 0 ) return 0 ;

这样没处理K<0的情况,这在dfs中是不会出现的,但这里由于从dfs中传递过来的,

res += dfs(left, k - 1) * getSmall(right, k - 2);

这里的k可能为1,所以就可能传进一个负数K了。

在test 7挂掉了,数据是这样的:N=172,K=44,按理来说根据二叉树的性质,这里能推倒出N应为一个奇数,偶数时应该为ANS应该为0.

然后结果却大于0,Debug中发现small[8][42]为1,可没有地方能让它赋值为1啊。。。

这就是因为传入了负数K,递归的次数会应为N而有限,所以递归没爆栈,可是当n=8,k=-63时,发生了件出乎意料又情理之中的事情。

small[8][-63]=c时,赋的就是small[8][42]的值。

通过这次Debug,晓得越界真是件可怕的事情。

贴AC后的爽图,娘的。

USACOTrainning.Cow Pedigrees

 

 

 

感谢:

http://hi.baidu.com/leokan/blog/item/a8fca034599fd0b3d0a2d3bd.html

你可能感兴趣的:(USACO)