洛谷p2661資訊傳遞
阿新 • • 發佈:2018-11-09
題目:
有 n 個同學(編號為 1到 n )正在玩一個資訊傳遞的遊戲。在遊戲裡每人都有一個固定的資訊傳遞物件,其中,編號為 i 的同學的資訊傳遞物件是編號為 Ti 的同學。
遊戲開始時,每人都只知道自己的生日。之後每一輪中,所有人會同時將自己當前所知的生日資訊告訴各自的資訊傳遞物件(注意:可能有人可以從若干人那裡獲取資訊, 但是每人只會把資訊告訴一個人,即自己的資訊傳遞物件)。當有人從別人口中得知自己的生日時,遊戲結束。請問該遊戲一共可以進行幾輪?
題目連結:資訊傳遞
分析:
昂 有向邊?跑tarjan?
剛剛做了兩道並查集的我偷偷看了一眼標籤
當一個人的生日被傳回來的時候說明出現了環,這個題目很顯然要求的是最小環,遊戲結束的輪數就是最小環的長度
可以考慮用並查集維護這個過程,每讀入一個數據,先檢查這兩點是否已經連通(成環),若已經成環則更新最小值(最小值=兩個節點分別到祖先的距離+1(這個1指這兩個節點之間連的一條邊)),若沒有成環則連一條邊,設這條邊是A→B的有向邊,那麼顯然有A到祖先節點的距離=B到祖先節點的距離+1
更新father的過程中,記錄一個當前搜尋到的x的父節點last,先走上去到x的最老的祖先節點,邊走邊路徑壓縮,然後回溯回來的時候把值一層層傳遞下來
放一下程式碼吧(其實特別短來著):
#include<bits/stdc++.h> using namespace std; inline int read(){ int cnt=0,f=1;char c; c=getchar(); while(!isdigit(c)){ if(c=='-')f=-f; c=getchar(); } while(isdigit(c)){ cnt=cnt*10+c-'0'; c=getchar(); } return cnt*f; } int n; int t; int fa[200005],d[200005]; int minn=1<<20; int get_father(int x){ if(fa[x]!=x){ int last=fa[x]; fa[x]=get_father(fa[x]); d[x]+=d[last]; } return fa[x]; } void check(int a,int b){ int x=get_father(a); int y=get_father(b); if(x!=y){fa[x]=y;d[a]=d[b]+1;} else minn=min(minn,d[a]+d[b]+1); return ; } int main(){ n=read(); for(register int i=1;i<=n;i++)fa[i]=i,d[i]=0; for(register int i=1;i<=n;i++){ t=read(); check(i,t); } printf("%d",minn); return 0; }
參考了一下洛谷第一篇題解&&神犇fsy部落格,真的是很神仙的思路誒,比tarjan又好寫又巧妙才不是因為我懶