【bzoj1149】 [CTSC2007]风玲Mobiles
题目意为:给一颗二叉树,每一次操作可以交换该子树的左右两颗子树,要将该树变为完全二叉树,求最小操作次数。
从根开始进行一遍DFS。记录每棵子树的大小size,如果左子树的size小于右子树的size那么答案+1。实际上并不需要真的将两颗子树交换。接下来就是处理无解的情况了。
我们进行分类讨论。
1. 由题意得树的最大深度max_deep-min_deep<=1。我们可以在DFS的过程中记录deep来实现。
2. 判断两颗子树交换后左子树的右儿子size小于右子树左儿子size的情况。通过观察我们发现,当max_deep==min_deep时,size_left==2^n。size_right==2^k。那么当两颗子树都不满足这个条件时即为无解
1 #include<algorithm> 2 #include<iostream> 3 #include<cstdlib> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 using namespace std; 8 9 #define N 200010 10 11 struct Node 12 { 13 int l,r,deep,data; 14 }tr[N<<1]; 15 16 int n,m; 17 int l,r,depl,depr; 18 int ans; 19 20 int a[N]; 21 22 void dfs(int k) 23 { 24 if (ans==-1) 25 return ; 26 if (tr[k].l!=-1) 27 dfs(tr[k].l); 28 if (tr[k].r!=-1) 29 dfs(tr[k].r); 30 if (ans==-1) 31 return ; 32 if (tr[k].l!=-1) 33 l=tr[tr[k].l].data; 34 else 35 l=1; 36 if (tr[k].r!=-1) 37 r=tr[tr[k].r].data; 38 else 39 r=1; 40 if (l==1) 41 depl=1; 42 else 43 depl=tr[tr[k].l].deep; 44 if (r==1) 45 depr=1; 46 else 47 depr=tr[tr[k].r].deep; 48 if ((abs(depl-depr)>1) || (!a[l] && !a[r] && l!=1 && r!=1)) 49 { 50 ans=-1; 51 return ; 52 } 53 else if (l<r) 54 ans++; 55 tr[k].deep=max(depl,depr)+1; 56 tr[k].data=l+r; 57 } 58 59 int main() 60 { 61 scanf("%d",&n); 62 for (int i=1;i<=200000;i<<=1) 63 a[i]=1; 64 for (int i=1;i<=n;i++) 65 scanf("%d%d",&tr[i].l,&tr[i].r); 66 dfs(1); 67 printf("%d",ans); 68 return 0; 69 }