20200305之发现环 (拓扑排序 || 并查集+dfs)
2020-04-07 12:23
976 查看
小明的实验室有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
vector<int>q //申请了1个动态一维数组q vector<int>q[N] //申请了一个二维数组q,q的每个元素是一个一维数组
第一种方法:拓扑排序
树形结构,就先把样例画成一棵树
我们可以知道,叶子结点都是度为1的结点,所以不是环。因此我们把度为1结点放入队列,并标记为1相当于从树中去掉。
然后我们来看这个度为1结点相连的结点。先将这个结点出队列,遍历和这个结点有连边的所有结点,如果被遍历到的结点已经访问过了,跳过这个结点。没有被访问过,就度数-1,再判断是否变成度数为1的叶子结点。是就入队列,设已访问过。然后while循环继续遍历队列中的结点。
剩下未曾进入队列的、未被访问过的自然就是在环上的结点,输出即可。
下面是AC代码:
#include <bits/stdc++.h> #include <vector> #include <queue> using namespace std; const int N=100001; int du[N]; //存放这个结点的度数 vector<int>a[N]; //每个顶点都是一个一维数组,存放与它有连边的结点 queue<int>q; int vis[N]; int main(){ int n; cin>>n; for(int i=0;i<n;i++){ int x,y; cin>>x>>y; a[x].push_back(y); //x结点与y有连边 a[y].push_back(x); //相应y结点与x也有连边 du[x]++; //分别度+1 du[y]++; } for(int i=1;i<=n;i++){ if(du[i]==1){ //叶子结点度为1肯定不在环上 q.push(i); //把这些结点先放入队列里 vis[i]=1; //表示已经访问过 } } while(!q.empty()){ int t=q.front(); q.pop(); int l=a[t].size(); for(int i=0;i<l;i++){ int temp=a[t][i]; if(vis[temp]) continue; du[temp]--; if(du[temp]==1){ vis[temp]=1; q.push(temp); } } } int k; for(k=1;k<=n;k++){ if(!vis[k]) printf("%d ",k); } printf("\n"); return 0; }
第二种方法:并查集+dfs
- 点赞
- 收藏
- 分享
- 文章举报
相关文章推荐
- 算法设计与分析—分治
- 20200310之和最大子序列 (动态规划)
- 20200310之种树 (动态规划 搜索)
- 20200312之第几天 (Excel)
- 20200314之新型导弹 (枚举 填空)
- 20200314之分苹果 (前缀和差分)
- 2019年第十届蓝桥杯(慢慢补)
- 算法设计与分析之 动态规划
- 开始记录
- C#接口笔记
- 20200313C#随手截图笔记
- Eplan截图笔记
- Driver files are not downloaded
- maven mybatis小结20200313
- jreble搜不到一直转圈或者提示商城没有的现象
- springboot2.2.6阿里镜像提示找不到
- 查看注解的作用
- 自己去阿里仓库找依赖遇到问题
- Youka:可创建任何YouTube视频的卡拉OK歌曲版本的免费网站
- 20200222 jzoj c组 生产武器(produce)