


【題意】
略
【解法】
暴力+剪枝
說實話一拿到題目最開始的想法是中序和中序對稱、前序和后序對稱,然而最后上手去寫以后發現這編程復雜度高到一定境界,還是暴力拯救世界的好
首先,怎么判定一棵子樹是不是對稱二叉樹
1 bool check(ll x,ll y) 2 { 3 if (x==-1&&y==-1) return true; // 皆為空 4 if (x==-1||y==-1) return false; // 一邊不為空 5 if (a[x]!=a[y]) return false; // 數值不相等 6 return ((check(l[x],r[y])&&check(r[x],l[y]))); 7 }
如果待判定的子樹的根節點為x,則只需要check(l[x],r[x])即可
然而對每個節點都判斷,很顯然是時間上是來不及的
需要剪枝
什么情況下完全不可能有對稱二叉樹
1、兩棵子樹節點數不同
2、兩棵子樹高度不同
3、兩棵子樹權值和/最大值/最小值不同
1 void dfs(ll rt,ll&h,ll&sz,ll&sum) 2 { // 節點,高度,節點數,權值和 3 if (rt<=0) 4 { 5 h=0,sz=0,sum=0; 6 return; 7 } 8 ll h1,h2,sz1,sz2,sm1,sm2; 9 dfs(l[rt],h1,sz1,sm1); 10 dfs(r[rt],h2,sz2,sm2); 11 if (h1==h2&&sz1==sz2&&sm1==sm2) 12 if (check(l[rt],r[rt])) 13 ans=max(ans,sz1+sz2+1); 14 h=max(h1,h2)+1; 15 sz=sz1+sz2+1; 16 sum=sm1+sm2+a[rt]; 17 }
實際上,只需要判斷高度+節點數就行
【代碼】
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N = 1000000+5; 4 typedef long long ll; 5 ll n; 6 ll l[N]={0},r[N]={0}; 7 ll a[N]; 8 ll ans; 9 bool check(ll x,ll y) 10 { 11 if (x==0&&y==0) return true; // 皆為空 12 if (a[x]!=a[y]) return false; 13 return ((check(l[x],r[y])&&check(r[x],l[y]))); 14 } 15 void dfs(ll rt,ll&h,ll&sz) 16 { 17 if (rt<=0) 18 { 19 h=0,sz=0; 20 return; 21 } 22 ll h1,h2,sz1,sz2; 23 dfs(l[rt],h1,sz1); 24 dfs(r[rt],h2,sz2); 25 if (h1==h2&&sz1==sz2) 26 if (check(l[rt],r[rt])) 27 ans=max(ans,sz1+sz2+1); 28 h=max(h1,h2)+1; 29 sz=sz1+sz2+1; 30 } 31 int main() 32 { 33 scanf("%lld",&n); 34 for (int i=1;i<=n;i++) 35 scanf("%lld",&a[i]); 36 for (int i=1;i<=n;i++) 37 { 38 scanf("%lld%lld",&l[i],&r[i]); 39 if (l[i]==-1) l[i]++; 40 if (r[i]==-1) r[i]++; 41 } 42 a[0]=-1; 43 ans=1; 44 ll h,sz; 45 dfs(1,h,sz); 46 printf("%lld",ans); 47 }
