发现环(并查集+DFS)

发现环(并查集+DFS)

问题描述

小明的实验室有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

分析

用并查集算法找到环,当两个点合并失败即两个节点的根节点相同时,表示该条边加入后图中已经形成环,改条边的两个点作为DFS的起点和终点。

代码实现

#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int N;
int from,end;
int flag[100005]={0};
int ans[100005]={0};
vector<int>map[100005];
void dfs(int x,int k)
{
	ans[k]=x;
	if(x==end)
	{
		sort(ans,ans+k+1);
		for(int i=0;i<=k;i++)
		cout<<ans[i]<<" ";
		return ; 
	}
	flag[x]=1;
	for(int i=0;i<map[x].size();i++)
	{
		if(!flag[map[x][i]])
		dfs(map[x][i],k+1);
	}
	flag[x]=0;
}
int find_root(int parent[],int x)
{
	int x_root=x;
	while(parent[x_root]!=-1)
	{
		x_root=parent[x_root];
	}
	return x_root;
}
int conio(int x,int y,int parent[],int rank[])
{
	int x_root=find_root(parent,x);
	int y_root=find_root(parent,y);
	if(x_root==y_root)
	return 0;
	else
	{
		if(rank[x_root]>rank[y_root])
		parent[y_root]=x_root;
		else if(rank[x_root]<rank[y_root])
		parent[x_root]=y_root;
		else if(rank[x_root]==rank[y_root])
		{
			parent[x_root]=y_root;
			rank[y_root]++;
		}
	}
}
int main(int argc, char *argv[]) {
	int i;
	cin>>N;
	int *parent=new int[N+1];
	int *rank=new int[N+1];
	for(i=1;i<=N;i++)
	{ 
	parent[i]=-1;
	rank[i]=1;
	} 
	for(i=1;i<=N;i++)
	{
		int a,b;
		cin>>a>>b;
		if(conio(a,b,parent,rank))
		{
			map[a].push_back(b);
			map[b].push_back(a);
		}
		else
		{
			from=a;
			end=b;
			break;
		}
	}
	dfs(from,0);
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值