1. 程式人生 > 其它 >For M_tree how to through pre_visit and post_visit to find how many kinds mid_visit?

For M_tree how to through pre_visit and post_visit to find how many kinds mid_visit?

技術標籤:考研機試刷題

Introduction

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 explain:

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 explain:

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.

case:

Input

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

Output

4
1
45
207352860

解題思路:

本質就是找到每一個根節點的子樹
因為是m叉樹,所以可以得到當前根節點的子樹有多少組合方式,再
去到每一顆子樹,如此遞迴直到找到所有葉子結點
比如 abejkcfghid jkebfghicda
找到先序序列的第一個節點和後序序列的最後一個節點,這個節點就是當前的根節點
當前的根→a bejk cfghi d jkeb fghic d a
↑ ↑ ↑ ↑ ↑ ↑
找到3個區間,說明這一層有三顆子樹
遍歷後序序列找到先序中根節點之後的節點,如果該點出現在根節點的前一個位置
說明只有一顆子樹,ans *= m (m叉樹)
不然就遍歷整個後序序列,統計子樹的個數k,然後算mCk ans*= mCk

對這些子樹所在的區間遞迴,直到只有一個節點,返回

程式碼實現:

#include<cstdio>
#include<vector>
#include<cstring>
#include<string>
#include<map>
using namespace std;
int ans, m;
char pre[27], post[27];
map<char, int> postidx;
//相應字母在post中的下標,因為每個節點都是唯一的,所以可以建立一個索引
void Count(int preS, int preE, int postS, int postE);
int mCk(int m, int k);

int main()
{
    while (scanf("%d %s %s", &m, pre, post) != EOF)
    {
        ans = 1;
        for (int i = 0; i<strlen(post); i++)
            postidx[post[i]] = i;
        Count(0, strlen(pre) - 1, 0, strlen(post) - 1);
        printf("%d\n", ans);
    }//while
    return 0;
}//main

void Count(int preS, int preE, int postS, int postE)//指示先序和後序某段區間
{
    if (preS >= preE)
        return;
    int i = preS + 1, cnt = 0;//cnt統計子樹的個數,i是標識當前樹的根節點的子樹的根節點,在pre中的下標
    int idx = postidx[pre[i]];
    while (i <= preE)
    {
        Count(i, i + idx - postS, postS, idx);
        cnt++;
        if (idx != postE - 1)//子樹不止一個,把要遞迴搜尋的樹的區間整體移動
        {
            i += idx - postS + 1;   //idx-postS是剛剛遞迴過的子樹的大小
                                  //i要跨過這個區間,找到下一個要搜尋的根節點
            postS = idx + 1;    //post的區間起始位置也要前進1位
            idx = postidx[pre[i]];//idx重新定位下一個要搜尋的子樹根節點在post中的下標
        }
        else
            break;//完成對當前區間中所有字數根節點的全部搜尋
    }
    ans *= mCk(m, cnt);//計算排列組合,cnt表示當前層有幾個子樹
}

int mCk(int m, int k)
{
    int numerator = 1, denominator = 1;
    for (int i = 0; i<k; i++, m--)
        numerator *= m;
    for (int i = 1; i <= k; i++)
        denominator *= i;
    return numerator / denominator;
}