Codeforces Round #397(Div. 1 + Div. 2 combined)E. Tree Folding【思维+Dfs】dalao们的解法真巧妙系列QAQ

224 篇文章 2 订阅

E. Tree Folding
time limit per test
2 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output

Vanya wants to minimize a tree. He can perform the following operation multiple times: choose a vertex v, and two disjoint (except for v) paths of equal length a0 = v, a1, ..., ak, and b0 = v, b1, ..., bk. Additionally, vertices a1, ..., ak, b1, ..., bk must not have any neighbours in the tree other than adjacent vertices of corresponding paths. After that, one of the paths may be merged into the other, that is, the vertices b1, ..., bk can be effectively erased:

Help Vanya determine if it possible to make the tree into a path via a sequence of described operations, and if the answer is positive, also determine the shortest length of such path.

Input

The first line of input contains the number of vertices n (2 ≤ n ≤ 2·105).

Next n - 1 lines describe edges of the tree. Each of these lines contains two space-separated integers u and v (1 ≤ u, v ≤ n, u ≠ v) — indices of endpoints of the corresponding edge. It is guaranteed that the given graph is a tree.

Output

If it is impossible to obtain a path, print -1. Otherwise, print the minimum number of edges in a possible path.

Examples
Input
6
1 2
2 3
2 4
4 5
1 6
Output
3
Input
7
1 2
1 3
3 4
1 5
5 6
6 7
Output
-1
Note

In the first sample case, a path of three edges is obtained after merging paths 2 - 1 - 6 and 2 - 4 - 5.

It is impossible to perform any operation in the second sample case. For example, it is impossible to merge paths 1 - 3 - 4 and 1 - 5 - 6, since vertex 6 additionally has a neighbour 7 that is not present in the corresponding path.


题目大意:

如果一个节点的两个子树是都是链,而且长度相同,那么两个子树就可以合并成一颗子树,问最后能够缩成最短是多长。


思路(思路源自:http://www.cnblogs.com/RUSH-D-CAT/p/6404742.html):


1、首先我们可以盲目以任意一点作为根去Dfs.我们不妨一开始设定根为1.

我们盲目的去Dfs.并且用set来去重记录一个节点有几种深度的子树.


2、对于每一个节点来讲:

①set.size()==0如果当前节点没有子树存在,那么这个节点就是作为一条链的端点出现。

②set.size()==1如果当前节点有子树存在,而且深度种类只有一种,那么显然可以将所有子树都合并称为一个子树.

③set.size()==2如果当前节点有两种深度的子树存在,那么如果他没有父节点(如果他就是根),那么我们就找到了一个合法合并的方式。

④set.size()==2如果当前节点有两种深度的子树存在,但是他不是根节点(他有父节点),那么我们可以考虑设定这个点为根,再进行一次Dfs.因为当前设定以1为根的时候,出现了不合法合并成一条链的子节点,那么以1为根就是不能最终合并成一条链的。所以我们考虑再进行一次Dfs,试一试是否有解。

⑤set.size()>2,无论怎样处理,肯定最终解都是-1.....


3、最终链的长度假设还是偶数,那么我们考虑在最中间的那个点作为根,将两侧的单链继续合并。


Ac代码:

#include<stdio.h>
#include<string.h>
#include<vector>
#include<set>
using namespace std;
int root,n;
vector<int >mp[200605];
int Dfs(int u,int from)
{
    set<int >s;
    for(int i=0;i<mp[u].size();i++)
    {
        int v=mp[u][i];
        if(v==from)continue;
        int tmp=Dfs(v,u);
        if(tmp==-1)return -1;
        s.insert(tmp+1);
    }
    if(s.size()==0)return 0;
    if(s.size()==1)return *s.begin();
    if(s.size()==2)
    {
        if(from==-1)
        {
            int sum=0;
            for(set<int>::iterator it=s.begin(); it!=s.end(); it++)
            {
                sum+=*it;
            }
            return sum;
        }
        else
        {
            root=u;
            return -1;
        }
    }
    return -1;
}
int main()
{
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n;i++)mp[i].clear();
        for(int i=1;i<=n-1;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            mp[x].push_back(y);
            mp[y].push_back(x);
        }
        root=1;
        int ans=Dfs(root,-1);
        if(ans==-1&&root!=1)ans=Dfs(root,-1);
        while(ans%2==0)ans/=2;
        printf("%d\n",ans);
    }
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值