Luogu P2661 信息傳遞
阿新 • • 發佈:2018-11-16
www. 感謝 size 並不會 cst ref target blank printf
傳送門
一眼就能看出來是個並查集 但是並不會寫...
看了一下題解說是並查集求最小環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(View Code"%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; }
Luogu P2661 信息傳遞