bfs

本文介绍了一种针对树形结构的特殊操作——折叠算法。通过特定条件下的路径合并操作,探讨了如何将任意树形结构简化为最短路径的问题。文章提供了一种使用广度优先搜索(bfs)的方法,通过从叶子节点开始逐步向上处理,最终确定是否能够将树转化为一条路径,并求得该路径的最短长度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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<bits/stdc++.h>
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(广度优先搜索)算法是一种用于遍历或搜索图结构的经典算法,其核心原理是从起点开始,逐层扩展搜索范围,直到找到目标节点或遍历完整个图。该算法特别适用于求解最短路径问题或扩散性质的区域问题[^1]。 ### BFS算法原理 BFS算法从初始状态(起点)出发,按照状态转换规则(图结构中的边),逐步遍历所有可能的状态(节点),直到找到目标状态(终点)。其核心思想是“先扩散后深入”,即每次处理当前层的所有节点,再进入下一层处理。这种逐层扩散的方式确保了BFS在首次到达目标节点时,所走的路径是最短的。 ### BFS算法实现方法 BFS算法通常使用队列(Queue)来实现,队列用于存储待处理的节点。具体步骤如下: 1. 将起点节点加入队列,并标记为已访问。 2. 当队列不为空时,取出队列中的第一个节点。 3. 对当前节点进行处理,例如检查是否为目标节点。 4. 遍历当前节点的所有相邻节点,如果未被访问,则标记为已访问,并加入队列。 5. 重复步骤2-4,直到找到目标节点或队列为空。 以下是一个简单的BFS算法实现示例,用于遍历图结构: ```python from collections import deque def bfs(graph, start): visited = set() # 用于记录已访问的节点 queue = deque([start]) # 初始化队列 visited.add(start) # 标记起点为已访问 while queue: node = queue.popleft() # 取出队列中的第一个节点 print(node) # 处理当前节点 # 遍历当前节点的所有相邻节点 for neighbor in graph[node]: if neighbor not in visited: visited.add(neighbor) # 标记为已访问 queue.append(neighbor) # 加入队列 ``` ### BFS算法的复杂度分析 BFS算法的时间复杂度和空间复杂度均与图中的节点数和边数相关。假设图中有 $V$ 个节点和 $E$ 条边,则时间复杂度为 $O(V + E)$,空间复杂度为 $O(V)$。这是因为BFS需要访问所有节点和边,并且队列可能存储最多 $V$ 个节点[^1]。 ### BFS算法的应用场景 BFS算法广泛应用于以下问题: 1. **走迷宫最短路径**:寻找从起点到终点的最短路径。 2. **数字按规则转换的最少次数**:例如,将一个数字转换为另一个数字所需的最少操作次数。 3. **棋盘上某个棋子N步后能到达的位置总数**:计算棋子在N步内可以到达的所有位置。 4. **病毒扩散计算**:模拟病毒在人群中的扩散过程。 5. **图像中连通块的计算**:识别图像中的连通区域[^1]。 ### BFS与DFS的比较 - **BFS**:通过队列实现,适合解决最短路径问题,但空间复杂度较高。 - **DFS**:通过递归或栈实现,适合解决需要遍历完整棵树的问题,但时间复杂度较高。 例如,在满二叉树的情况下,BFS的空间复杂度为 $O(N)$,而DFS的空间复杂度为 $O(\log N)$[^2]。 ### BFS的优势与局限性 - **优势**:BFS可以保证首次到达目标节点时的路径是最短的,适用于最短路径问题。 - **局限性**:BFS的空间复杂度较高,尤其在处理大规模图时,可能需要较多的内存资源[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值