有向图找环( 并查集 )

假设有一条 x − > y x->y x>y 的有向边,当建立连接时,更新 x x x的父节点,同时更新 x x x 到父节点的距离 l e n [ x ] = l e n [ y ] + 1 len[x]=len[y]+1 len[x]=len[y]+1
若父节点相同说明存在环,环的大小为 l e n [ x ] + l e n [ y ] + 1 。 len[x]+len[y]+1。 len[x]+len[y]+1

#include<bits/stdc++.h>
#define LL long long
#define pii pair<LL,LL>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn=2e5+5;
const int inf=0x3f3f3f3f;
const LL MOD=1e9+7;

int n,tmp,f[maxn],len[maxn],Min=inf;
int getfind(int x){
    if(f[x]!=x){//查找祖先的过程中更新路径
        int last=f[x];//记录父节点
        f[x]=getfind(f[x]);//更新父节点
        len[x]+=len[last];//回溯过程更新路径 +父节点到祖先节点的路径
    }return f[x];
}
void Merge(int x,int y){
    int k1=getfind(x);
    int k2=getfind(y);
    if(k1!=k2){
        f[k1]=k2;
        len[x]=len[y]+1;
    }else{
        Min=min(Min,len[x]+len[y]+1);
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) f[i]=i;
    for(int i=1;i<=n;i++){
        scanf("%d",&tmp);
        Merge(i,tmp);
    }
    printf("%d\n",Min);
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值