您的位置:首页 > 其它

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

  • 点赞
  • 收藏
  • 分享
  • 文章举报
是IMI呀 发布了38 篇原创文章 · 获赞 0 · 访问量 723 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: