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 }
40 pts

正解: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 }
View Code

然后就意想不到地RE了九个点(上述代码是AC的),查了大概两个小时(?),还一直以为是tarjan的锅,结果发现是Dfs的时候“else dfs(x,nxt[fa],step+1);”这句话,第二个参量应该是nxt[fa],我写成了nxt[x],这不就死循环了嘛。xswl。

 

自己还是太菜了。(哭)

posted @ 2018-08-22 20:44  cellur925&Chemist  阅读(148)  评论(0编辑  收藏  举报