前序和后序遍历
https://www.acwing.com/problem/content/1611/
思路:
由于n只有30,直接暴力枚举,虽说理论上限很高可能会超时,但是其实dfs过程中剪枝了许多。
关键在如何dfs,由于知道前序和后序,无法确定每次左右子树的长度,所以每次枚举左子树的长度,又因为总长一定,现在左右子树长度都知道了,又因为题目中说了,只要其中一种方案即可,这个题目的方案满足乘法原理,只要方案大于1,直接break即可。
注意:
1.l1>r1的时候return 1,因为此时为空树,而空树也算做一种合法方案。
2.当pre[l1]!=post[r2]的时候直接return 0,因为此时肯定不是合法的。
#include <iostream>
using namespace std;
const int N = 40;
int n;
int pre[N], post[N];
int dfs(int l1, int r1, int l2, int r2, string& in)
{
if (l1 > r1) return 1;
if (pre[l1] != post[r2]) return 0;
int cnt = 0;
for (int i = l1; i <= r1; i ++ ) // 枚举左子树包含的节点数量
{
string lin, rin;
int lcnt = dfs(l1 + 1, i, l2, l2 + i - l1 - 1, lin);
int rcnt = dfs(i + 1, r1, l2 + i - l1 - 1 + 1, r2 - 1, rin);
if (lcnt && rcnt)
{
in = lin + to_string(pre[l1]) + ' ' + rin;
cnt += lcnt * rcnt;
if (cnt > 1) break;
}
}
return cnt;
}
int main()
{
cin >> n;
for (int i = 0; i < n; i ++ ) cin >> pre[i];
for (int i = 0; i < n; i ++ ) cin >> post[i];
string in;
int cnt = dfs(0, n - 1, 0, n - 1, in);
if (cnt > 1) puts("No");
else puts("Yes");
in.pop_back();
cout << in << endl;
return 0;
}