Luogu P2921 在农场万圣节 【tarjan in 有向图】 By cellur925
上来就想到既直接又简单的暴力方法,顺着每个房间的下一个走下去就好了,但是没想到最坏情况会达到1e5,100000的数据铁定超时。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 5 using namespace std; 6 7 int n; 8 int nex[100090],ans[10090]; 9 bool vis[100090]; 10 11 int dfs(int u) 12 { 13 int sum=1,x=u;bool flag=1; 14 memset(vis,0,sizeof(vis)); 15 vis[u]=1; 16 while(flag) 17 { 18 int y=nex[x]; 19 if(vis[y]) flag=0; 20 vis[y]=1;x=y;sum++; 21 } 22 sum--; 23 return sum; 24 } 25 26 int main() 27 { 28 scanf("%d",&n); 29 for(int i=1;i<=n;i++) 30 scanf("%d",&nex[i]); 31 for(int i=1;i<=n;i++) 32 ans[i]=dfs(i); 33 for(int i=1;i<=n;i++) 34 printf("%d\n",ans[i]); 35 return 0; 36 }
正解:tarjan算法。
去到奶牛去过的隔间,显然这和环有关,我们手写一下样例(样例真香)就可以发现每个点只有两种情况:
1.在环中 这样的点答案为环的大小。
2.通过一些点才能与环相连 这样的点答案为环的大小+到达环的最小距离
于是我们就可以跑一遍tarjan,求出每个环的大小,对于那些不直接在环上的点,dfs一下即可。
Code
1 #include<cstdio> 2 # 3 include<algorithm> 4 #include<stack> 5 #define maxn 100090 6 7 using namespace std; 8 9 int n,x,tot,dfs_clock,scc_cnt; 10 int head[maxn],dfn[maxn],scc[maxn],low[maxn],ans[maxn],size[maxn]; 11 struct node{ 12 int next,to; 13 }edge[maxn]; 14 stack<int>s; 15 16 void add(int x,int y) 17 { 18 edge[++tot].next=head[x]; 19 edge[tot].to=y; 20 head[x]=tot; 21 } 22 23 void tarjan(int u) 24 { 25 dfn[u]=low[u]=++dfs_clock; 26 s.push(u); 27 for(int i=head[u];i;i=edge[i].next) 28 { 29 int v=edge[i].to; 30 if(!dfn[v]) 31 { 32 tarjan(v); 33 low[u]=min(low[v],low[u]); 34 } 35 else if(!scc[v]) low[u]=min(low[u],dfn[v]); 36 } 37 if(dfn[u]==low[u]) 38 { 39 scc_cnt++; 40 while(1) 41 { 42 int p=s.top(); 43 s.pop(); 44 scc[p]=scc_cnt; 45 if(u==p) break; 46 } 47 } 48 } 49 50 void dfs(int u,int fa,int step) 51 { 52 if(ans[fa]) 53 { 54 ans[u]=ans[fa]+step; 55 return ; 56 } 57 else dfs(u,edge[head[fa]].to,step+1); 58 } 59 60 int main() 61 { 62 scanf("%d",&n); 63 for(int i=1;i<=n;i++) 64 { 65 scanf("%d",&x); 66 add(i,x); 67 if(i==x) ans[i]=1; 68 } 69 for(int i=1;i<=n;i++) 70 if(!dfn[i]) tarjan(i); 71 for(int i=1;i<=n;i++) 72 size[scc[i]]++; 73 for(int i=1;i<=n;i++) 74 if(size[scc[i]]>1) ans[i]=size[scc[i]]; 75 for(int i=1;i<=n;i++) 76 if(!ans[i]) dfs(i,edge[head[i]].to,1); 77 for(int i=1;i<=n;i++) 78 printf("%d\n",ans[i]); 79 return 0; 80 }
然后就意想不到地RE了九个点(上述代码是AC的),查了大概两个小时(?),还一直以为是tarjan的锅,结果发现是Dfs的时候“else dfs(x,nxt[fa],step+1);”这句话,第二个参量应该是nxt[fa],我写成了nxt[x],这不就死循环了嘛。xswl。
自己还是太菜了。(哭)
独立意志与自由思想是必须争的,且须以生死力争。