codeforces 765E dfs

来源:互联网 发布:淘宝店铺怎么刷单 编辑:程序博客网 时间:2024/05/20 05:11

题意:每次从一棵树中找两根长度相同、起点相同的直链并删去其中一根。重复这个操作,求可以得到的最短直链的长度。需要注意的是树即使已经被删成直链了,如果长度是偶数还可以继续删的。
示意图
问题的关键是找到树中的“特殊点”,也就是我上面的图中的所有红点。“特殊点”的特点是它的度>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 0
原创粉丝点击