天天看点

【BZOJ1149】【APIO2007】风铃(完全二叉树+dp)

Description

【BZOJ1149】【APIO2007】风铃(完全二叉树+dp)
【BZOJ1149】【APIO2007】风铃(完全二叉树+dp)
【BZOJ1149】【APIO2007】风铃(完全二叉树+dp)

Input

【BZOJ1149】【APIO2007】风铃(完全二叉树+dp)

Output

输出仅包含一个整数。表示最少需要多少次交换能使风铃满足Ike的条件。如果不可能满足,输出-1。

Sample Input

6

2 3

-1 4

5 6

-1 -1

-1 -1

-1 -1

Sample Output

2

题目大意:给定一棵完全二叉树,可以交换某个节点的左右儿子,求最少交换多少次数,可以使所有的叶节点深度相差不超过1,且深度较大的叶节点都在深度较小的叶节点左侧。

题解:

无解的情况好多……

首先,最大和最小的节点深度超过1就无解了。其次,如果最大深度和最小深度节点分别在一颗子树的左子树和右子树中,也是无解的。

因此,只要先做一遍DFS预处理出节点深度的有关数据,再dp就好了,注意分类就行了。

代码如下:

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<math.h>
#define ll long long
#define inf 0x7f7f7f7f
using namespace std; 
int n,l[],r[],ans,minn=inf,maxx; 
void dfs(int u,int dep)
{
    if(u==-)
    {
        maxx=max(maxx,dep);
        minn=min(minn,dep);
        return ;
    }
    dfs(l[u],dep+);dfs(r[u],dep+);
    return ;
}
int work(int u,int dep)
{
    int x=,y=;
    if(u==-)
    {
        if(dep==minn) return ;
        return ;
    }
    x=work(l[u],dep+),y=work(r[u],dep+);
    if((x== && y==) || (x== && y==) || (x== && y==)) ans++;  
    if(x== && y==){puts("-1");exit();}  
    return (x|y); 
}
int main()
{
    scanf("%d",&n);
    for(int i=;i<=n;i++) scanf("%d%d",&l[i],&r[i]);
    dfs(,);
    if(maxx-minn>) return puts("-1"),;
    if(maxx==minn) return puts("0"),;
    work(,);
    printf("%d\n",ans);
    return ;
}
           

继续阅读