题目
题目详解
上面的手写已经很详细了,我这里做个总结:
这是一个最小环问题。
此法限制条件:每个点的出度必须为1(方便计算环里面的结点个数)
具体做法:
-
用并查集思路做每条边的连接。
//TODO 并查集的查找动作,查找的同时记一波数 int find(int i,int& cnt){ cnt++; if(i==f[i])return i; return find(f[i],cnt);//TODO 注意为了方便每次能查找根结点的同时计算这个环上的元素个数,所以不要去路径压缩! } ... f[i] = dst;//TODO 由于数据给出i的传递对象是dst,所以把i的出度设为dst ...
-
一旦出现连接dst会产生环,则更新环的大小(这里利用所有元素出度为1的性质简化了判环和计算环元素个数的过程)。
//TODO 并查集的查找动作,查找的同时记一波数 int find(int i,int& cnt){ cnt++; if(i==f[i])return i; return find(f[i],cnt);//TODO 注意为了方便每次能查找根结点的同时计算这个环上的元素个数,所以不要去路径压缩! } ... if(find(dst,cnt)==i){//TODO 一旦产生出度为0的点连接了他的子节点(只要这个结点的根结点是i,则这个结点时i的子节点),则产生环 ret = min(cnt,ret); } ...
解题代码
#include<bits/stdc++.h>
#define MAXN 200005
using namespace std;
int f[MAXN];
//TODO 并查集的查找动作,查找的同时记一波数
int find(int i,int& cnt){
cnt++;
if(i==f[i])return i;
return find(f[i],cnt);
}
int main(){
ios::sync_with_stdio(false);
int n;
cin>>n;
for(int i=1;i<=n;i++)
f[i] = i;
int ret = INT_MAX;
for(int i=1;i<=n;i++){
int dst,cnt = 0;
cin>>dst;
if(find(dst,cnt)==i){//TODO 一旦产生出度为0的点连接了他的子节点则产生环
ret = min(cnt,ret);
}else{//TODO 没有产生环则,正常连接
f[i] = dst;
}
}
cout<<ret;
return 0;
}