首页 > 代码库 > 洛谷 P2661 信息传递 Label:并查集?

洛谷 P2661 信息传递 Label:并查集?

题目描述

有n个同学(编号为1到n)正在玩一个信息传递的游戏。在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学。

游戏开始时,每人都只知道自己的生日。之后每一轮中,所有人会同时将自己当前所知的生日信息告诉各自的信息传递对象(注意:可能有人可以从若干人那里获取信息,但是每人只会把信息告诉一个人,即自己的信息传递对象)。当有人从别人口中得知自己的生日时,游戏结束。请问该游戏一共可以进行几轮?

输入输出格式

输入格式:

 

输入共2行。

第1行包含1个正整数n表示n个人。

第2行包含n个用空格隔开的正整数T1,T2,……,Tn其中第i个整数Ti示编号为i

的同学的信息传递对象是编号为Ti的同学,Ti≤n且Ti≠i

数据保证游戏一定会结束。

 

输出格式:

 

输出共 1 行,包含 1 个整数,表示游戏一共可以进行多少轮。

 

输入输出样例

输入样例#1:
52 4 2 3 1
输出样例#1:
3

说明

样例1解释

技术分享

游戏的流程如图所示。当进行完第 3 轮游戏后, 4 号玩家会听到 2 号玩家告诉他自

己的生日,所以答案为 3。当然,第 3 轮游戏后, 2 号玩家、 3 号玩家都能从自己的消息

来源得知自己的生日,同样符合游戏结束的条件。

对于 30%的数据, n ≤ 200;

对于 60%的数据, n ≤ 2500;

对于 100%的数据, n ≤ 200000。

代码

 1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 #include<vector> 6 #define INF 0x3f3f3f3f 7 using namespace std; 8 vector<int> G[500005],rG[500005],vs; 9 int N,tot=INF,ans,used[500005],cmp[500005],dep[500005],rank[500005],pa[500005];int k=0;10 //并查集 11 void init_bingchaji(){12     for(int i=1;i<=200000;i++){13         rank[i]=0;pa[i]=i;14     }15 }16 int Find(int a){17     if(pa[a]==a) return a;18     else return pa[a]=Find(pa[a]);19 }20 void unite(int a,int b){21     int ta=Find(a),pb=Find(b);22     if(rank[ta]>rank[pb]) pa[pb]=ta;23     else{24         pa[ta]=b;25         if(rank[ta]==rank[pb]) rank[pb]++;26     }27 }28 29 //强联通分量30 void init_qingliantong(){31     ;32 }33 void add_edge(int a,int b){34     G[a].push_back(b);35     rG[b].push_back(a);36 }37 void dfs(int v){38     used[v]=1;39     for(int i=0;i<G[v].size();i++){40         if(!used[G[v][i]]) dfs(G[v][i]);41     }42     vs.push_back(v);43 }44 void rdfs(int v,int k,int depth){45     used[v]=1;46     dep[v]=depth;47     cmp[v]=k;48     for(int i=0;i<rG[v].size();i++){49         if(!used[rG[v][i]]) rdfs(rG[v][i],k,depth+1);50         51         int& now=rG[v][i];52         if(cmp[v]==cmp[now]&&Find(v)==Find(now)){53             for(int j=0;j<G[v].size();j++){54 //                printf("v=%d G[v][j]=%d \n",v,G[v][j]);55                 if(Find(now)==Find(G[v][j])){56                     tot=min(tot,dep[G[v][j]]-dep[v]+1);57 //                    printf("%d %d\n",v,G[v][j]);58                 }59             }60         }61         else unite(v,rG[v][i]);62     }63     for(int i=0;i<rG[v].size();i++){64         if(cmp[v]==cmp[rG[v][i]]) continue;65         66     }67 }68 void scc(){69     for(int i=1;i<=N;i++){70         if(!used[i]) dfs(i);71     }72 //    for(int i=0;i<vs.size();i++) printf("%d ",vs[i]);73     memset(used,0,sizeof(used));74     init_bingchaji();75     for(int i=vs.size()-1;i>=0;i--){76         if(!used[vs[i]]) {77 //            init_bingchaji();78             pa[vs[i]]=vs[i];79             rdfs(vs[i],k++,1);80         }81     }82 }83 84 85 int main(){86 //    freopen("01.in","r",stdin);87     scanf("%d",&N);88     for(int i=1;i<=N;i++){89         int tmp;scanf("%d",&tmp);90         add_edge(i,tmp);91     }92     scc();93 //    for(int i=1;i<=5;i++) printf("%d\n",cmp[i]);94     printf("%d\n",tot);95 }

非常恶心的 强联通

 

以下为并查集特别版

 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6  7 using namespace std; 8  9 queue <int>q;10 int n,ans,father[200001],vis[200001],ent[200001];11 12 int main()13 {14     cin>>n;15     ans=n;16     int x,i,j;17     for(int i=1;i<=n;++i)18     {19         scanf("%d",&father[i]);20         ++ent[father[i]];21     }22     for(int i=1;i<=n;++i)23     {24         if(ent[i]==0)25         {26             q.push(i);27             vis[i]=1;28         }29     }30     while(!q.empty())31     {32         x=q.front();33         q.pop();34         --ent[father[x]];35         if(ent[father[x]]==0)36         {37             vis[father[x]]=1;38             q.push(father[x]);39         }40     }41     for(int i=1;i<=n;++i)42     {43         if(ent[i]!=0&&vis[i]!=1)44         {45             vis[i]=1;46             j=father[i];47             x=1;48             while(vis[j]==0)49             {50                 vis[j]=1;51                 j=father[j];52                 ++x;53             }54             if(ans>=x)ans=x;55         }56     57     }58     printf("%d",ans);59     puts("");60     return 0;61 }

 

洛谷 P2661 信息传递 Label:并查集?