zoj 1500 Pre-Post-erous!

本篇實爲轉藏,感謝原文:

http://blog.csdn.net/xsbailong/article/details/7220756

爲使讀者能夠更好的理解代碼,這裏對源代碼做一些講解。

We are all familiar with pre-order, in-order and post-order traversals of binary trees. A common problem in data structure classes is to find the pre-order traversal of a binary tree when given the in-order and post-order traversals. Alternatively, you can find the post-order traversal when given the in-order and pre-order. However, in general you cannot determine the in-order traversal of a tree when given its pre-order and post-order traversals. Consider the four binary trees below:

All of these trees have the same pre-order and post-order traversals. This phenomenon is not restricted to binary trees, but holds for general m-ary trees as well.


Input

Input will consist of multiple problem instances. Each instance will consist of a line of the form

m s1 s2

indicating that the trees are m-ary trees, s1 is the pre-order traversal and s2 is the post-order traversal. All traversal strings will consist of lowercase alphabetic characters. For all input instances, 1 <= m <= 20 and the length of s1 and s2 will be between 1 and 26 inclusive. If the length of s1 is k (which is the same as the length of s2, of course), the first k letters of the alphabet will be used in the strings. An input line of 0 will terminate the input.


Output

For each problem instance, you should output one line containing the number of possible trees which would result in the pre-order and post-order traversals for the instance. All output values will be within the range of a 32-bit signed integer. For each problem instance, you are guaranteed that there is at least one tree with the given pre-order and post-order traversals.


Sample Input

2 abc cba
2 abc bca
10 abc bca
13 abejkcfghid jkebfghicda
0


Sample Output

4
1
45
207352860


題意:一個k叉樹,給定其前序和後序遍歷,問其中序遍歷方式有多少種。

思路:給定前序和中序無法唯一的確定一棵k叉樹,但是每一個結點所在的深度

      卻是唯一的。本題可用遞歸進行計算。每次遞歸獲得每層結點分佈的可能性。

      舉例 :13 abejkcfghid jkebfghicda

     顯然a,b容易確定,由後序知 j,k,e必定爲 b 的後代。對 j,k,e 遞歸可獲得j,k,e的位置關係。同理其它元素都可以確定自己所在的層數。

     對於每一層,計算組合數C(m,n)可知(即從m箇中選n個),這裏的 m表示的是m叉樹,而n 則表示該層結點數。

/*這部分爲我的理解,非原作者所寫:
做這道題,首先建議對一棵樹不侷限於二叉樹自己做一下前序遍歷和後序遍歷試一試。用紙寫出遍歷順序即可,你可以發現,前序的第一個肯定是根a,第二個是根的一個兒子b,那麼,根的第二個兒子c在哪裏呢?注意後序遍歷,b之前的肯定是b的子孫,這些子孫在前序遍歷中一定在c的前面。於是可以由此得出所有a的兒子。假設樹a有solve(a)種方法,那麼b有solve(b)种放法,c有solve(c)種方法,solve(a)=C(k,son)*solve(b)*solve(c)遞歸即可
*/

//給原作者代碼增添了一些註釋
#include <iostream>  
#include <cstdio>  
#include <string.h>  
using namespace std;  
int k;  
 
//組合數 
int C( int m,int n )  
{  
    int i,mul=1;  
    for( i=0;i<n;i++ )  
        mul*=(m-i);  
    for( i=n;i>=1;i-- )  
        mul/=i;  
    return mul;  
}  
 
//pre爲第一個數組,post爲第二個數組 
int solve( int m,char *pre,char *post )  
{  
    int i=1,j=0,re=1,son=0; //i爲pre下標,j爲post下標  
                            //re統計結果,son表示子樹個數。  
    while( i<m )  
    {	//pre[i]實際上就是樹根的兒子
        while( post[j]!=pre[i] )  
            j++; 
		//找到一個兒子
        son++;  
		//對找到的兒子的子樹遞歸,看有多少種
		//子樹的長度(j-(i-1)+1)
		//pre+i,出去根節點的起始位置
        re*=solve( j+2-i,pre+i,post+i-1 ); //乘法法則
		//i變爲根的下一個孩子
		//i+子樹長度(j-(i-1)+1);
        i=j+2;  
    }  
    return re*C( k,son );  
}  
  
int main()  
{  
    char pre[30],post[30];  
    while( scanf( "%d",&k ) && k )  
    {  
        scanf( "%s%s",pre,post );  
        printf( "%d\n",solve( strlen(pre),pre,post ) );  
    }  
    return 0;  
}  



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章