【蓝桥杯有点意思】发现环 dfs+并查集

题目链接戳这里

前言

找有向图中的环很简单,因为tarjan是一个现成的模板,而无向图找环就有点复杂了,比较考察dfs的能力。


如何找无向图中的环呢?
首先,我们把一个边的两边加入并查集,当我们新加入的边已经在并查集内时,这个边就构成了环。这个边的两端可以看作环的起点和终点。
然后我们从起点开始dfs到终点,这中间的路径就是环上的点。

所以我们从起点开始,如果遇到了没访问过的点,我们就继续从该点开始遍历。如果走到死路,我们就要回溯了。回溯很重要,如果不回溯的话,那么走到死路之后这个算法就不能继续下去了。

代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+7;
vector<int> G[maxn];
int n,s,t;
int p[maxn];
int ans[maxn];
int vis[maxn];
void init()
{
	for(int i=0;i<maxn;i++) p[i] = i;
}
int find(int x)
{
	if(x==p[x]) return x;
	return p[x] = find(p[x]);
}
void unite(int x,int y)
{
	x = find(x);
	y = find(y);
	if(x==y) return;
	p[x] = y;
}
bool same(int x,int y)
{
	return find(x)==find(y);
}
void dfs(int now,int stp)
{
	ans[stp] = now;
	if(now==t)
	{
		sort(ans,ans+stp+1);
		for(int i=0;i<=stp;i++) printf("%d ",ans[i]);
		return;
	}
	vis[now] = 1;
	for(int i=0;i<G[now].size();i++)
	{
		int v = G[now][i];
		if(!vis[v])
		{
			vis[v] = 1;
			dfs(v,stp+1);
			vis[v] = 0;
		}
	}
}
int main()
{
	init();
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		if(same(a,b)) 
		{
			s = a;
			t = b;
			continue;
		}
		unite(a,b);
		G[a].push_back(b);
		G[b].push_back(a);
	}
	dfs(s,0);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/KIKO_caoyue/article/details/87915335