问题描述
  小明的实验室有N台电脑,编号1~N。原本这N台电脑之间有N-1条数据链接相连,恰好构成一个树形网络。在树形网络上,任意两台电脑之间有唯一的路径相连。

  不过在最近一次维护网络时,管理员误操作使得某两台电脑之间增加了一条数据链接,于是网络中出现了环路。环路上的电脑由于两两之间不再是只有一条路径,使得这些电脑上的数据传输出现了BUG。

  为了恢复正常传输。小明需要找到所有在环路上的电脑,你能帮助他吗?

输入格式
  第一行包含一个整数N。
  以下N行每行两个整数a和b,表示a和b之间有一条数据链接相连。

  对于30%的数据,1 <= N <= 1000
  对于100%的数据, 1 <= N <= 100000, 1 <= a, b <= N

  输入保证合法。

输出格式
  按从小到大的顺序输出在环路上的电脑的编号,中间由一个空格分隔。
样例输入
5
1 2
3 1
2 4
2 5
5 3
样例输出
1 2 3 5

解题思路:这一题可以用并查集的数据结构判断是否有环,用dfs递归找到环。

并查集:并查集是用来管理元素分组情况的数据结构。注意并查集并不能高效的进行分割,可以高效地进行:
  • 查询a,b是否同组。
  • 合并a,b所在的组。

具体实现用树形结构,如果a,b所在组相同,则a,b有相同的根结点。合并两组时即让一组的根向另一组相连。

为了避免树形结构下发生退化的情况,在并查集中可以如下操作:

  • 对于每颗树,记录这颗树的高度.(rank)
  • 合并时,rank小的向rank大的连

此外还可以路径压缩,即把每个结点都直接与其根结点相连,树的高度为2.在查询过程中查询过程中递归的所有节点都直接指向根结点。

此时为方便起见,即使树的高度改变,我们也不修改rank的值(rank只是在合并时决定谁向谁连根)。

具体见下实现代码。


若(u,v)之间有边,则将u,v放入同一组。如果在放入u,v之前已经在同一组,即从u可以到v,那么加入边(u,v)后就形成了一个环。

以u或v作为环的起点,用dfs方法遍历每个顶点相邻的顶点,看最后是否回到了起点,如果沿某一路径回到起点,则说明这些

顶点在这个环内。


实现代码:

#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std; const int Max_N = ; //输入
int n;
int s;//环的起点
vector<int> G[Max_N+];//图
vector<int> V;//记录环
bool visited[Max_N+];//结点是否访问过(避免重复访问) int par[Max_N+];//并查集
int rank[Max_N+];//并查集高度 //初始化并查集
void init(int n)
{
for(int i=; i<=n; i++){//刚开始互相没有边相连
par[i] = i;
}
} //找下标x的根
int find(int x)
{
return x==par[x] ? x:par[x] = find(par[x]);//par[x] = find(par[x])即路径压缩
} //合并
void unite(int x,int y)
{
x = find(x); y=find(y);//先找到他们的根 if( x==y ){
return;//同根 直接返回
} if( rank[x]<rank[y] ){
par[x] = y;//将x所在的树合并在y下
}
else
{
par[y] = x;
if( rank[x]==rank[y] ){//如果高度相同 更新rank[x]
rank[x]++;
}
}
} //x,y是否在同一组 即是否同根
bool same(int x,int y)
{
return find(x)==find(y);
}
//dfs
bool dfs(int u)
{
if( visited[u] )//如果最后访问的结点回到起点,则在环内
{
if( u==s )
{
return true;
}
return false;//否则不在环内
} visited[u] = true;//u已经访问过 for(int i=; i<G[u].size(); i++)//遍历顶点 u 的相邻边
{
int v = G[u][i];//下一个顶点
if( dfs(v) )//在环内
{
V.push_back(v);
return true;
}
}
return false;//遍历所有边都不在环内
} void solve()
{
dfs(s); sort(V.begin(),V.end()); vector<int>::iterator it;
for( it=V.begin(); it!=V.end(); it++)
{
printf("%d ",*it);
}
printf("\n");
} int main()
{
scanf("%d",&n);
init(n);
while( n-- )
{
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v); G[v].push_back(u);
if( same(u,v) ){//u,v已经有路径了
s = u;//起点下标
}
unite(u,v);
} solve(); return ;
}

蓝桥杯 试题 历届试题 发现环 并查集+dfs的更多相关文章

  1. [蓝桥杯]PREV-23.历届试题_数字游戏

    问题描述 栋栋正在和同学们玩一个数字游戏. 游戏的规则是这样的:栋栋和同学们一共n个人围坐在一圈.栋栋首先说出数字1.接下来,坐在栋栋左手边的同学要说下一个数字2.再下面的一个同学要从上一个同学说的数 ...

  2. [蓝桥杯]PREV-12.历届试题_危险系数

    问题描述 抗日战争时期,冀中平原的地道战曾发挥重要作用. 地道的多个站点间有通道连接,形成了庞大的网络.但也有隐患,当敌人发现了某个站点后,其它站点间可能因此会失去联系. 我们来定义一个危险系数DF( ...

  3. [蓝桥杯]PREV-44.历届试题_青蛙跳杯子

    问题描述 X星球的流行宠物是青蛙,一般有两种颜色:白色和黑色. X星球的居民喜欢把它们放在一排茶杯里,这样可以观察它们跳来跳去. 如下图,有一排杯子,左边的一个是空着的,右边的杯子,每个里边有一只青蛙 ...

  4. [蓝桥杯]PREV-27.历届试题_蚂蚁感冒

    问题描述 长100厘米的细长直杆子上有n只蚂蚁.它们的头有的朝左,有的朝右. 每只蚂蚁都只能沿着杆子向前爬,速度是1厘米/秒. 当两只蚂蚁碰面时,它们会同时掉头往相反的方向爬行. 这些蚂蚁中,有1只蚂 ...

  5. [蓝桥杯]PREV-26.历届试题_最大子阵

    问题描述 给定一个n*m的矩阵A,求A中的一个非空子矩阵,使这个子矩阵中的元素和最大. 其中,A的子矩阵指在A中行和列均连续的一块. 输入格式 输入的第一行包含两个整数n, m,分别表示矩阵A的行数和 ...

  6. [蓝桥杯]PREV-25.历届试题_城市建设

    问题描述 栋栋居住在一个繁华的C市中,然而,这个城市的道路大都年久失修.市长准备重新修一些路以方便市民,于是找到了栋栋,希望栋栋能帮助他. C市中有n个比较重要的地点,市长希望这些地点重点被考虑.现在 ...

  7. [蓝桥杯]PREV-22.历届试题_国王的烦恼

    问题描述 C国由n个小岛组成,为了方便小岛之间联络,C国在小岛间建立了m座大桥,每座大桥连接两座小岛.两个小岛间可能存在多座桥连接.然而,由于海水冲刷,有一些大桥面临着不能使用的危险. 如果两个小岛间 ...

  8. [蓝桥杯]PREV-21.历届试题_回文数字

    问题描述 观察数字:, 都有一个共同的特征,无论从左到右读还是从右向左读,都是相同的.这样的数字叫做:回文数字. 本题要求你找到一些5位或6位的十进制数字.满足如下要求: 该数字的各个数位之和等于输入 ...

  9. [蓝桥杯]PREV-19.历届试题_九宫重排

    题目描述: 代码如下: #include <stdio.h> #include <stdlib.h> #include <string.h> #define N 1 ...

随机推荐

  1. js 运动函数篇(二) (加速度运动、弹性运动、重力场运动(多方向+碰撞检测+重力加速度+能量损失运动)拖拽运动)层层深入

    前言:         本人纯小白一个,有很多地方理解的没有各位大牛那么透彻,如有错误,请各位大牛指出斧正!小弟感激不尽.         本篇文章为您分析一下原生JS写加速度运动.弹性运动.重力场运 ...

  2. 突然地心血来潮,为 MaixPy( k210 micropython ) 添加看门狗(WDT) C 模块的开发过程记录,给后来的人做开发参考。

    事情是前几天群里有人说做个看门狗不难吧,5分钟的事情,然后我就怼了几句,后来才发现,原来真的没有看门狗模块鸭. 那好吧,那我就写一下好了,今天是(2020年4月30日)想着最后一天了,不如做点什么有价 ...

  3. 【集群实战】Rsync试题-异机数据备份解决方案

    企业案例:Rsync上机实战考试题: 某公司有一台Web服务器,里面的数据很重要,但是如果硬盘坏了,数据就会丢失,现在领导要求你把数据在其它机器上做一个周期性定时备份. 要求如下: 每天晚上00点整在 ...

  4. windows服务程序的编写

    服务编写https://blog.csdn.net/lanuage/article/details/77937407 #include <windows.h> #include <s ...

  5. React技术栈——Redux

    Redux 1.Redux是什么?   Redux对于JavaScript应用而言是一个可预测状态的容器.换言之,它是一个应用数据流框架,而不是传统的像underscore.js或者AngularJs ...

  6. 跟风微信小程序,生鲜水果店如何借力小程序每天多赚2万块?

    公司旁边的水果店,虽然是一家实体店,但老板有一颗爱玩互联网的心. 老板非常重视线上的营销推广,什么新的线上推广方式都爱尝试一下.公众号大热时做了自己的微信公众号,并且有自己的微信商城,不过线上的销售一 ...

  7. 图论--2-SAT--暴力染色法求字典序最小模版

    #include <cstdio> #include <cstring> #include <stack> #include <queue> #incl ...

  8. django源码分析——静态文件staticfiles中间件

    本文环境python3.5.2,django1.10.x系列 1.在上一篇文章中已经分析过handler的处理过程,其中load_middleware就是将配置的中间件进行初始化,然后调用相应的设置方 ...

  9. P2766 最长不下降子序列问题 网络流重温

    P2766 最长不下降子序列问题 这个题目还是比较简单的,第一问就是LIS 第二问和第三问都是网络流. 第二问要怎么用网络流写呢,首先,每一个只能用一次,所以要拆点. 其次,我们求的是长度为s的不下降 ...

  10. P2765 魔术球问题 网络流二十四题重温

    P2765 魔术球问题 知识点::最小点覆盖 这个题目要拆点,这个不是因为每一个球只能用一次,而是因为我们要求最小点覆盖,所以要拆点来写. 思路: 首先拆点,然后就是开始建边,因为建边的条件是要求他们 ...