題目描述
一棵有點權的有根樹如果滿足以下條件,則被軒軒稱爲對稱二叉樹:
- 二叉樹;
- 將這棵樹所有節點的左右子樹交換,新樹和原樹對應位置的結構相同且點權相等。
下圖中節點內的數字爲權值,節點外的 idid 表示節點編號。
現在給出一棵二叉樹,希望你找出它的一棵子樹,該子樹爲對稱二叉樹,且節點數 最多。請輸出這棵子樹的節點數。
注意:只有樹根的樹也是對稱二叉樹。本題中約定,以節點 TT 爲子樹根的一棵“子 樹”指的是:節點TT和它的全部後代節點構成的二叉樹。
輸入格式
第一行一個正整數 nn,表示給定的樹的節點的數目,規定節點編號 1 \sim n1∼n,其中節點 11 是樹根。
第二行 nn 個正整數,用一個空格分隔,第 ii 個正整數 v_ivi 代表節點 ii 的權值。
接下來 nn 行,每行兩個正整數 l_i, r_ili,ri,分別表示節點 ii 的左右孩子的編號。如果不存在左 / 右孩子,則以 -1−1 表示。兩個數之間用一個空格隔開。
輸出格式
輸出文件共一行,包含一個整數,表示給定的樹的最大對稱二叉子樹的節點數。
輸入輸出樣例
輸入 #1複製
2 1 3 2 -1 -1 -1
輸出 #1複製
1
輸入 #2複製
10 2 2 5 5 5 5 4 4 2 3 9 10 -1 -1 -1 -1 -1 -1 -1 -1 -1 2 3 4 5 6 -1 -1 7 8
輸出 #2複製
3
說明/提示
【輸入輸出樣例 1 說明】
最大的對稱二叉子樹爲以節點 22 爲樹根的子樹,節點數爲 11。
【輸入輸出樣例 2 說明】
最大的對稱二叉子樹爲以節點 77 爲樹根的子樹,節點數爲 33。
【數據規模與約定】
共 2525 個測試點。
v_i ≤ 1000vi≤1000。
測試點 1 \sim 3, n ≤ 101∼3,n≤10,保證根結點的左子樹的所有節點都沒有右孩子,根結點的右 子樹的所有節點都沒有左孩子。
測試點 4 \sim 8, n ≤ 104∼8,n≤10。
測試點 9 \sim 12, n ≤ 10^59∼12,n≤105,保證輸入是一棵“滿二叉樹” 。
測試點 13 \sim 16, n ≤ 10^513∼16,n≤105,保證輸入是一棵“完全二叉樹”。
測試點 17 \sim 20, n ≤ 10^517∼20,n≤105,保證輸入的樹的點權均爲 11。
測試點 21 \sim 25, n ≤ 10^621∼25,n≤106。
本題約定:
層次:節點的層次從根開始定義起,根爲第一層,根的孩子爲第二層。樹中任一節 點的層次等於其父親節點的層次加 11。
樹的深度:樹中節點的最大層次稱爲樹的深度。
滿二叉樹:設二叉樹的深度爲 hh,且二叉樹有 2h-12h−1 個節點,這就是滿二叉樹。
完全二叉樹:設二叉樹的深度爲 hh,除第 hh 層外,其它各層的結點數都達到最大 個數,第 hh 層所有的結點都連續集中在最左邊,這就是完全二叉樹。
思路
搜索好題,1年後的我再來這道題有了一定的思路。不斷換根找二叉樹,然後判斷是否對稱,將得到的二叉樹節點加起來,最後比較最大的節點數。實現方法用dfs。
#include <stdio.h>
#include <iostream>
#define N 1000001
using namespace std;
int l[N],r[N],a[N],s(1),n,f;
//l[i]存節點i的左兒子,r[i]存節點i的右兒子,a[i]節點i的權值
int dfs(int x,int y,int s)//x和y是兩個節點,s爲節點總數
{
if(x==-1 && y==-1) return 0;//如果沒有節點就可以爬了
if(x==-1 || y==-1 && x!=y)//是否對稱
{
f=1;
return 0;
}
if(a[x]!=a[y])//是否對稱
{
f=1;
return 0;
}
return dfs(l[x],r[y],2)+dfs(r[x],l[y],2)+s;//爲什麼這樣寫,可以自己畫個圖理解一下。
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
register int i;
cin>>n;
for(i=1;i<=n;i++)
{
cin>>a[i];
}
for(i=1;i<=n;i++)
{
cin>>l[i]>>r[i];
}
for(i=1;i<=n;i++)
{
int maxn(dfs(l[i],r[i],3));//3的原因是還要加上自己本身
if(maxn>s && f==0) s=maxn;
f=0;
}
cout<<s<<endl;
return 0;
}