信息传递

[TIMEGATE]

https://www.luogu.org/problem/P2661

【解题思路】

把每个同学看成一个点,信息的传递就是在他们之间连有向边,游戏轮数就是求最小环。

图论求最小环,我在里面看到了并查集。

假如说信息由A传递给B,那么就连一条由A指向B的边,同时更新A的父节点,A到它的父节点的路径长也就是B到它的父节点的路径长+1。

这样我们就建立好了一个图,之后信息传递的所有环节都按照这些路径。游戏结束的轮数,也就是这个图里最小环的长度。

如果有两个点祖先节点相同,那么就可以构成一个环,长度为两个点到祖先节点长度之和+1。

和下面的并查集有点不一样的。

【code】

 1 #include <cstdio>
 2 #include <cstring> 
 3 #include <stack>
 4 using namespace std;
 5 const int N=200005;
 6 int next[N],head[N],end[N],vis[N],dfn[N],low[N];
 7 int i,n,tt,t,a,ans=1<<30,sum,v;
 8 stack<int> s,ss;
 9 void add(int u,int v){
10     next[++t]=head[u];
11     head[u]=t;
12     end[t]=v;
13 }
14 void tarjan(int u){
15     int i;
16     tt++;
17     dfn[u]=tt;
18     low[u]=tt;
19     s.push(u);
20     vis[u]=1;
21     for(i=head[u];i;i=next[i]){
22         v=end[i];
23         if(dfn[v]==-1){
24             tarjan(v);
25             low[u]=min(low[u],low[v]);
26         }
27         else if(vis[v]==1)
28         low[u]=min(low[u],dfn[v]);
29     }
30     if(dfn[u]==low[u]){
31         sum=0;
32         while(1){
33             v=s.top();
34             s.pop();
35             sum++;
36             vis[v]=0;
37             if(u==v)break;
38         }
39         if(sum>1&&sum<ans)ans=sum;
40     }
41 }
42 int main(){
43     //freopen("message.in","r",stdin);
44     //freopen("message.out","w",stdout);
45     memset(dfn,-1,sizeof(dfn));
46     scanf("%d",&n);
47     for(i=1;i<=n;i++){
48         scanf("%d",&a);
49         add(i,a);
50     }
51     for (i=1;i<=n;i++)
52         if(dfn[i]==-1)
53         tarjan(i);
54     printf("%d",ans);
55     return 0;
56 }

 

posted @ 2019-08-20 12:58  GTR_PaulFrank  阅读(155)  评论(0编辑  收藏  举报