以洛谷P2661信息传递为例总结找环的常见的几种方法
题目链接:https://www.luogu.com.cn/problem/P2661
法一:并查集
当两个点x和y之间存在一条边,且他们的祖先都相同时,就会形成一个环,环的大小为dis[x]+dis[y]+1
#include <bits/stdc++.h> #define Pair pair<int,int> using namespace std; typedef long long ll; const int MAXN=2e5+5; const int INF=0x7fffffff; int n,min_=INF; int f[MAXN],dis[MAXN]; void init() { for(int i=1;i<=n;i++) f[i]=i; } int find_(int v) { if(f[v]!=v) { int last=f[v]; f[v]=find_(f[v]); dis[v]+=dis[last]; } return f[v]; } void merge_(int x,int y) { int tx=find_(x),ty=find_(y); if(tx!=ty) { f[tx]=ty;dis[x]=dis[y]+1; } else min_=min(min_,dis[x]+dis[y]+1); } int main() { ios::sync_with_stdio(false); cin.tie(0); cin>>n; init(); for(int i=1;i<=n;i++) { int x;cin>>x; merge_(i,x); } cout<<min_<<endl; return 0; }
法二:拓扑排序找环
思路:对一个有向图进行拓扑排序可判断该图是否存在环,如果有拓扑序列则无环,反之则有
#include <bits/stdc++.h> #define Pair pair<int,int> using namespace std; typedef long long ll; const int MAXN=2e5+5; const int INF=0x7fffffff; int n,min_=INF,head[MAXN],tot,in[MAXN],visit[MAXN]; struct node { int to,nxt; }e[MAXN<<1]; void add(int x,int y) { e[tot].to=y;e[tot].nxt=head[x];head[x]=tot++; } vector<int>v1;queue<int>q; void topusort() { while(!q.empty()) { int u=q.front();q.pop(); v1.push_back(u);visit[u]=1; for(int i=head[u];~i;i=e[i].nxt) { int v=e[i].to;in[v]--; if(in[v]==0)q.push(v); } } } int dfs(int x) { visit[x]=1; for(int i=head[x];~i;i=e[i].nxt) { int v=e[i].to; if(!visit[v]) return dfs(v)+1; } return 1; } int main() { ios::sync_with_stdio(false); cin.tie(0); cin>>n;memset(head,-1,sizeof(head)); for(int i=1;i<=n;i++) { int x;cin>>x; add(i,x);in[x]++; } for(int i=1;i<=n;i++) if(!in[i])q.push(i); topusort(); for(int i=1;i<=n;i++) { if(!visit[i])min_=min(dfs(i),min_); } cout<<min_<<endl; return 0; }