发现环(并查集+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
    评论
好的,以下是使用C++实现基准法+并查集+DFS方法来解决无向图求桥的问题的代码: ```cpp #include <iostream> #include <vector> #include <cstring> using namespace std; const int MAXN = 1e5 + 5; int n, m, tot, num; int head[MAXN], dfn[MAXN], low[MAXN], fa[MAXN], bridge[MAXN]; bool vis[MAXN]; struct Edge { int to, next; } edge[MAXN << 1]; inline void add_edge(int u, int v) { edge[++tot].to = v; edge[tot].next = head[u]; head[u] = tot; } int find(int x) { if (x == fa[x]) return x; return fa[x] = find(fa[x]); } void tarjan(int u, int pre) { dfn[u] = low[u] = ++num; vis[u] = true; for (int i = head[u]; i; i = edge[i].next) { int v = edge[i].to; if (!dfn[v]) { tarjan(v, i); low[u] = min(low[u], low[v]); if (dfn[u] < low[v]) bridge[i] = bridge[i ^ 1] = true; // 标记桥 else fa[v] = u; // 合并连通块 } else if (i != (pre ^ 1)) { low[u] = min(low[u], dfn[v]); fa[u] = find(v); } } } void dfs(int u) { vis[u] = true; for (int i = head[u]; i; i = edge[i].next) { int v = edge[i].to; if (!vis[v]) { if (!bridge[i]) cout << u << " " << v << endl; // 输出桥 dfs(v); } } } int main() { cin >> n >> m; tot = 1; for (int i = 1; i <= m; i++) { int u, v; cin >> u >> v; add_edge(u, v); add_edge(v, u); } for (int i = 1; i <= n; i++) fa[i] = i; // 初始化并查集 tarjan(1, 0); memset(vis, false, sizeof(vis)); dfs(1); return 0; } ``` 代码中使用了基准法+并查集+DFS方法来求无向图中的桥,具体实现过程如下: 1. 首先进行图的输入,并将边存储到邻接表中; 2. 定义一个并查集,用于维护连通块; 3. 使用Tarjan算法进行DFS遍历,对于每个节点u,进行如下处理: - 对于u的每个邻接节点v,如果v未被访问过,则对v进行DFS遍历; - 在回溯时,如果u的某个邻接节点v的dfn值小于u,则说明(u,v)不是桥,将(u,v)所对应的桥标记为false; - 如果u的某个邻接节点v的dfn值大于等于u,则说明(u,v)是桥,将(u,v)所对应的桥标记为true,并在这里进行并查集合并操作; 4. 对于所有的桥,输出桥两端节点的编号。 希望能够帮助到你!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值