P2921 [USACO08DEC]在農場萬聖節
阿新 • • 發佈:2018-11-01
一道不錯的記搜題。
由於每一個人點的出度只能是1,所以我們不難發現:每一條在環上的邊只能屬於一條環。換句話說:任何一條邊頂多屬於一個環。這樣我們就可以用簡單的記搜來實現。
設為從點開始最多能到達的點的總個數,那麼顯然,當在某個環中,=其他環上的點的f的值;當不在環中時,=從出發最先能到達的環中的點與的距離+。
具體的實現細節見程式碼。
Code:
#include<cstdio> #include<iostream> using namespace std; const int MAXN=100020; int n,nxt[MAXN],fst,dfn[MAXN],huan[MAXN],f[MAXN]; inline int read() { int x=0; char ch=getchar(); while(ch<'0'||'9'<ch) ch=getchar(); while('0'<=ch&&ch<='9') { x=(x <<3)+(x <<1)+(ch-'0'); ch=getchar(); } return x; } void dfs(int x,int tim) { if(nxt[x]==x) { f[x]=1; return; }//一定記得判斷自環的情況 if(f[nxt[x]]>0) { f[x]=f[nxt[x]]+1; return; } dfn[x]=tim; if(dfn[nxt[x]]>0) { huan[x]=1; fst=nxt[x];//huan變數幫助判斷當前點是否在環上 f[x]=dfn[x]-dfn[nxt[x]]+1; //記錄dfs序:當某個點通往一個已被搜到的點nxt[x],說明從nxt[x]到x的路徑+單向邊w(x,nxt[x])已經構成了一個環。 //顯然這個環的長度=dfn[x]-dfn[nxt[x]]+1; return; } dfs(nxt[x],tim+1); if(huan[nxt[x]]==1) { huan[x]=1; f[x]=f[nxt[x]]; if(x==fst) huan[x]=0; return; } f[x]=f[nxt[x]]+1; return; } int main() { n=read(); for(int i=1;i<=n;i++) nxt[i]=read(); for(int i=1;i<=n;i++) { fst=0; if(!dfn[i]) dfs(i,1); } for(int i=1;i<=n;i++) cout<<f[i]<<'\n'; return 0; }