标签:深度 判断 nbsp color ref org line 更新 题解
一眼就能看出来是个并查集 但是并不会写...
看了一下题解说是并查集求最小环qwq
所以,每次加入第i个小同学,判断如果他要告诉的小同学k最后会告诉他(也就是转回来了),
就说明出现了一个环,这时更新一下最小环;
否则就记一下他要告诉的小同学fa[x](为下一个环做铺垫)
(如果已经找到环就不记,否则下次有小同学指向这个环的时候就会进入死循环(感谢题解))
因为每个点的出度都是1,所以当某几个点已经形成了一个环的时候,他们就不可能属于别的环了,
也就是说每个点只能属于0(入度 = 0)或1个环,
可以得出当前这个点形成的环一定是它所能形成的最优解(最短的)!
当发现环的时候,在getfa里面用一个depth记录深度(环的长度);
至于注意事项...一开始我写的是
int getfa(int x,int &d) {
d++;
if(fa[x] == x)
return x;
return fa[x] = getfa(fa[x],d);
}
然而wa了,对照题解发现最后一句是错的qaq
于是我通过自己写了一堆测试数据才想明白:
因为每次判断都要调用一次getfa函数,所以即使没有找到环,经过的小同学的fa[]也是动态变化的,
这就导致当最后找到环的时候,中间的很多步骤都被跳过了,
并且由于depth每次清零,所以最后得到的depth并不是真正的答案。
解决方案:不改变fa[x]
return getfa(fa[x],d);
(其实我感觉把每个点的步数记下来也可以qwq但是没写出来...以后再说吧x)
完整代码:
#include<cstdio> #define min(x,y) (x)<(y)?(x):(y) using namespace std; int fa[1000005],n,k,dpth,ans = 10000005; int getfa(int x,int &d) { d++; if(fa[x] == x) return x; return getfa(fa[x],d); } int main() { scanf("%d",&n); for(int i = 1; i <= n; i++) fa[i] = i; for(int i = 1; i <= n; i++) { scanf("%d",&k); dpth = 0; if(getfa(k,dpth) == i) ans = min(ans,dpth); else fa[i] = k; } printf("%d",ans); return 0; }
标签:深度 判断 nbsp color ref org line 更新 题解
原文地址:https://www.cnblogs.com/mogeko/p/9966926.html