codeforces 765E dfs

题意:每次从一棵树中找两根长度相同、起点相同的直链并删去其中一根。重复这个操作,求可以得到的最短直链的长度。需要注意的是树即使已经被删成直链了,如果长度是偶数还可以继续删的。
示意图
问题的关键是找到树中的“特殊点”,也就是我上面的图中的所有红点。“特殊点”的特点是它的度>2,且与它相连的直链长度不全相等,即以它为起点,不经过其他度>2的点,到达叶子节点的路径有至少两条,且长度不全相等。
容易看出:若特殊点超过1个,结果必是-1;如果上述路径有三种及以上的长度,结果也是-1。不然,结果就是这两种长度之和,然后再除2直到不为偶数。
看出这个结论后就非常简单了:先对任一点建dfs树,用set存起每个点的节点的返回值,如果set.size>=3直接-1,如果==2就说明这个点是特殊点,再以这个点为起点建树做一遍。如果==1说明是普通点,直接+1返回上一层。
此外还需判断没有特殊点的情况。答案不一定直接就是cut(N-1),比如4 4 1 4 2 4 3这组数据,还得瞎搞一下,不再赘述。

#include<stdio.h>
#include<vector>
#include<set>
const int maxn=200020;
std::vector<int>edge[maxn];
int N,q;
int cut(int t){
    while(!(t&1))t>>=1;
    return t;
}
int dfs(int n,int pre){
    int deg=edge[n].size();
    if(deg==1)return 1;
    else if(deg==2)return 1+dfs((pre==edge[n][0])?edge[n][1]:edge[n][0],n);
    else{
        std::set<int>s;
        for(int i=0;i<deg;i++)if(edge[n][i]!=pre)
            s.insert(dfs(edge[n][i],n));
        if(s.size()==1)return *s.begin()+1;
        if(q)printf("-1\n"),exit(0);
        if(pre)q=1,s.insert(dfs(pre,n));
        if(s.size()>=3)printf("-1\n"),exit(0);
        printf("%d\n",cut(*s.begin()+*s.rbegin()));
        exit(0);
    };
}
int main(){
    scanf("%d",&N);
    for(int i=1;i<N;i++){
        scanf("%d%d",&u,&v);
        edge[u].push_back(v); edge[v].push_back(u);
    }
    for(int i=1;i<=N;i++)if(edge[i].size()>2)
        return 0*printf("%d",cut(dfs(i,0)));
    printf("%d",cut(N-1));
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值