Evanyou Blog 彩带

洛谷P3621风铃

传送门啦

分析:

这个题看起来像是个树形dp,嗯,就是看起来像。

所以我们就按树形dp的思路去分析就好了,这个题是一个树形dp的变形题。

和以前建树是一样的,我们用邻接表来进行储存。利用邻接表的特性,我们可以先加左边的点,再加右边的点,这样遍历的时候就可以先左后右了。

分析题意后我们设立几个数组:

(邻接表的就不说了,大家应该都会吧)

f [ i ] :表示使 i 这棵子树满足条件,所需要的最小的步数。

dep[ i ]:表示 i 这一个点的深度

maxdep[ i ]:表示 i 这个点的子树中风铃的最大深度

mindep[ i ]:同理表示 i 这个点的子树中风铃的最小深度

最后就是怎么样去写转移方程啦。

通过读题我们可以知道,在一棵树一定是一棵二叉树,所以我们就只需要将两棵子树相加就好了。

完成了???

并没有,我们是不是忘记了题目里的条件,题目中要求我们选一个满足下面两个条件的风铃:

(1) 所有的玩具都在同一层(也就是说,每个玩具到天花板之间的杆的个数是一样的)或至多相差一层。

(2) 对于两个相差一层的玩具,左边的玩具比右边的玩具要更靠下一点。

所以我们在状态转移方程里加一个小小的判断

if((abs(maxdep[c[1]] - mindep[c[2]]) > 1) || (abs(mindep[c[1]] - maxdep[c[2]]) > 1) || (maxdep[c[1]] > mindep[c[2]] && maxdep[c[2]] > mindep[c[1]])){

    printf("-1");
    exit(0);
}

这次是真的完成了??

是哒

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 400005;

inline int read(){
    int f = 1 , x = 0;
    char ch = getchar();
    while(ch > '9' || ch < '0'){if(ch == '-')f = -1;ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + ch - '0';ch = getchar();}
    return x * f;
}

int n,u,v;
struct Edge{
    int from,to,next;
}edge[maxn << 1];
int head[maxn],tot;
int f[maxn],w[maxn],cnt,c[maxn],dep[maxn];
int maxdep[maxn],mindep[maxn];

void add(int u,int v){
    edge[++tot].from = u;
    edge[tot].to = v;
    edge[tot].next = head[u];
    head[u] = tot;
}

void dfs(int x,int fa){
    for(int i=head[x];i;i=edge[i].next){
        int v = edge[i].to;
        if(v != fa){
            dep[v] = dep[x] + 1;
            dfs(v , x);
            mindep[x] = min(mindep[x] , mindep[v]);
            maxdep[x] = max(maxdep[x] , maxdep[v]);
        }
    }
    if(w[x] == -1)
        mindep[x] = maxdep[x] = dep[x];
    else {
        int num = 0;
        for(int i=head[x];i;i=edge[i].next){
            int v = edge[i].to;
            if(v != fa)
                c[++num] = v;//两个儿子 
        }
        if((abs(maxdep[c[1]] - mindep[c[2]]) > 1) 
            || (abs(mindep[c[1]] - maxdep[c[2]]) > 1) 
            || (maxdep[c[1]] > mindep[c[2]] && maxdep[c[2]] > mindep[c[1]])){
                printf("-1");
                exit(0);
            }
        f[x] = f[c[1]] + f[c[2]] + (mindep[c[1]] < maxdep[c[2]] ? 1 : 0);
    }
}
        
int main(){
    n = read();
    cnt = n;
    for(int i=1;i<=n;i++){
        u = read(); v = read();
        if(v == -1){
            v = ++cnt;
            w[cnt] = -1;
        }
        add(v , i);  add(i , v);
        if(u == -1){
            u = ++cnt;
            w[cnt] = -1;
        }
        add(i , u); add(u , i);
    }
    memset(mindep , 0x3f , sizeof(mindep));
    memset(maxdep , 0 , sizeof(maxdep));
    dfs(1 , 0);
    printf("%d\n",f[1]);
    return 0;
}

 

posted @ 2018-10-28 19:42  Stephen_F  阅读(117)  评论(0编辑  收藏  举报