下一棵树
Description
农场上有N(1<=N<=1000)棵树。在上过计算机课后,Lin发现所有的树实际上都是严格的二叉树,二叉树的每个非叶结点都恰好有两个子结点,Lin给每个结点一个数表示以这个结点为根的子树的叶结点数。然后,Lin按照先序遍历的结果把和结点相关的数列出作为它的特征序列。但是,他只列出了与根结点和所有的左子结点相关的数。
在这种方法表示完所有的树后,Lin发现:
- 所有的树有同样多的叶结点。
- 所有的树有不同的特征序列。
- 所有可能的严格的二叉树都在农场上。
所以,Lin决定把这些特征序列排序,然后希望给出一棵树的特征序列,求出紧接着的一个序列。
Analysis
这是树结构基础里比较有难度的一题,首先要读懂题目..特征序列是一棵树根和按照先序遍历的所有左子节点,因为是严格二叉树,所以每棵树的特征序列都是不同的。既然这样就可以根据特征序列建树。根右面的第一个节点一定是左子树的根,然后利用我们在扩展二叉树里的思想,直接递归求出左子树的结束点然后开始右子树的探索并返回右子树的结束点。而当根为1时,此树结束。
建完树之后就要找下一棵树,即从后往前找到第一个可以变动的点。而点能否变动如何判断呢,如果自己小于其根-1,那么自身值就可以+1,右子树-1,在确定自身之后,前面不变,后面的所有值都要最小,即全部为1。如果没有可以变动的点,就输出“0”。
Code
#include <bits/stdc++.h>
using namespace std;
int n,cnt,num[100010],s[100010],fa[100010],son[2][100010],place[100010];
int search(int sub,int le){
if(sub>=n||num[sub+1]>=s[le])
return sub;
int s1=cnt+1,s2=cnt+2;
s[s1]=num[sub+1],son[0][le]=s1,place[sub+1]=s1;
s[s2]=s[le]-num[sub+1],son[1][le]=s2;
fa[s1]=fa[s2]=le;
cnt+=2;
int end=search(sub+1,s1);
return search(end,s2);
}
int main(){
freopen("test.in","r",stdin);
freopen("test.out","w",stdout);
cin>>n;
for(int i=1;i<=n;i++)
cin>>num[i];
cnt=1,s[1]=num[1],place[1]=1;
search(1,1);
for(int i=n;i>=2;i--)
if(s[fa[place[i]]]-s[place[i]]>1)
{
for(int j=1;j<i;j++)
cout<<num[j]<<" ";
cout<<num[i]+1<<" ";
for(int j=i+1;j<n;j++)
cout<<"1 ";
cout<<"1\n";
return 0;
}
cout<<"0"<<endl;
return 0;
}