bfs

E. Tree Folding
time limit per test2 seconds
memory limit per test512 megabytes
inputstandard input
outputstandard 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.

题意:给你一棵树,如果从一个顶点开始存在两条到达叶节点的路径,并且这两条路径的长度相等,且每条路径上除了这个顶点外其它的定点与非该路径的的顶点没有边相连,那么我们可以执行一种操作,这个操作是把这两条路径合并成一条路径,也就是吧两条路径中的其中一条路径删除掉,问经过若干次这种操作之后,这棵树能不能变成一条路径,如果能,输出所有可能的路径中最短的那个路径的长度,如果不能,则输出-1.

解题思路:
我们分析题意可以得出,如果存在,则最后只有一种答案,因为只要满足执行操作的条件,就必须删除其中一条边,不删除的话,最后不可能得到单一路径,而两条边是等价的,所以删除哪条边对最后的结果没有影响,所以题目中那个让你找出最短的边是故意误导你,所以不用管它,只需要判断是否存在,判断的方法是从每个叶节点开始bfs,边删除节点边记录每个顶点能够到达的叶节点的长度,如果最后有某个顶点到达的叶节点的长度有三种或以上,则不存在解。特别需要注意的是储存这棵树时要用set来储存,因为在bfs过程中需要不断的删除边,所以用set比较方便,另外,用set的话会把重复的距离给自动屏蔽掉,便于我们判断。

#include
using namespace std;
const int maxn = 2e5 + 10;
int n;
set<int> Edge[maxn];//保存每个定点相连的顶点
set<int> Dis[maxn];//保存每个顶点与之能够到达的叶节点的距离
queue<int> Q;
bool visit[maxn];
int cal(int len)
{
    while(len%2 == 0)
    {
        len /= 2;
    }
    return len;
}
int bfs()
{
    memset(visit,false,sizeof(visit));
    while(!Q.empty())
    {
        int u = Q.front();
        Q.pop();
        if(visit[u]) continue;
        if(Edge[u].size() == 1)//顶点u是叶节点
        {
            if(Dis[u].size() == 1)//只有一个能够到达的叶节点
            {
                int v = *Edge[u].begin();
                Edge[u].erase(v);
                Edge[v].erase(u);
                Q.push(v);
                Dis[v].insert(*Dis[u].begin() + 1);
                visit[u] = true;
            }
        }
        else if(Edge[u].size() == 0)//删除的就剩最后一个顶点
        {
            if(Dis[u].size() >= 3)//无法形成单一路径
            {
                return -1;
            }
            else if(Dis[u].size() == 1)
            {
                return cal(*Dis[u].begin());
            }
            else if(Dis[u].size() == 2)
            {
                return cal(*Dis[u].begin() + *(++Dis[u].begin()));
            }
        }
    }
    return -1;
}
int main()
{
        scanf("%d",&n);
        int u,v;
        while(!Q.empty()) Q.pop();
        for(int i = 1; i <= n - 1; i++)
        {
            scanf("%d%d",&u,&v);
            Edge[u].insert(v);
            Edge[v].insert(u);
        }
        for(int i = 1; i <= n; i++)
        {
            if(Edge[i].size() == 1)
            {
                Q.push(i);//将所有叶节点加入队列
                Dis[i].insert(0);//初始化,为bfs做准备
            }
        }
        printf("%d\n",bfs());
        return 0;
}

你可能感兴趣的:(搜索,bfs,bfs)