1. 程式人生 > >[USACO08DEC]在農場萬聖節Trick or Treat on the Farm

[USACO08DEC]在農場萬聖節Trick or Treat on the Farm

urn www oot 最短距離 head col reat UC https

題目傳送門

solution

首先看到這題,題目要求回到經過的點,那麽很明顯是形成了一個環,那麽很容易想到是Tarjan,仔細一想,一個點只有兩種情況,要麽在環中,要麽通過一條鏈與環相接。那麽思路便很明顯了,先縮點,記錄各個環的大小,在環內的點的Ans值便是環的大小,在環外的點的Ans=點到環的最短距離+環的大小。

但註意要特判環大小為1的情況。

貼代碼

#include<bits/stdc++.h>
using namespace std;
const int Maxn=100005;
int next[Maxn];
int ans[Maxn];
int head[Maxn],cnt;
struct
road { int to,next; }e[Maxn*2]; void add(int a,int b) { cnt++; e[cnt].to=b; e[cnt].next=head[a]; head[a]=cnt; } int sum,color[Maxn],low[Maxn],ins[Maxn],tim[Maxn],sta[Maxn],top=1,col; int Lemon[Maxn]; void Tarjan(int x) { sum++; tim[x]=low[x]=sum; sta[top]=x; top++; ins[x]=1
; for(int i=head[x];i!=0;i=e[i].next) { if(ins[e[i].to]==0) { Tarjan(e[i].to); low[x]=min(low[x],low[e[i].to]); } else if(ins[e[i].to]==1) low[x]=min(low[x],tim[e[i].to]); } if(tim[x]==low[x]) { col++; do
{ top--; color[sta[top]]=col; ins[sta[top]]=-1; }while(sta[top]!=x); } return ; } void search(int root,int x,int step) { if(ans[x]!=0) { ans[root]=ans[x]+step; return ; } else search(root,next[x],step+1); } int main() { int n; cin>>n; for(int i=1;i<=n;i++) { scanf("%d",&next[i]); add(i,next[i]); if(next[i]==i) ans[i]=1;//註意特判環為1的情況。 } for(int i=1;i<=n;i++) if(ins[i]==0) Tarjan(i); for(int i=1;i<=n;i++) Lemon[color[i]]++;//記錄環的大小 for(int i=1;i<=n;i++) if(Lemon[color[i]]!=1) ans[i]=Lemon[color[i]];//處理在環內的點 for(int i=1;i<=n;i++) if(ans[i]==0) search(i,next[i],1);//處理在環外的點。 for(int i=1;i<=n;i++) printf("%d\n",ans[i]); return 0; }

[USACO08DEC]在農場萬聖節Trick or Treat on the Farm