1. 程式人生 > >下一棵樹

下一棵樹

clas 個數 lac 判斷 top 列排序 class 相關 難度

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

下一棵樹