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;
}