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

Posted Radiumlrb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷 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:
5
2 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:并查集?的主要内容,如果未能解决你的问题,请参考以下文章

Luogu P2661 信息传递

P2661 信息传递

洛谷——P2661 信息传递

洛谷 P2661信息传递

洛谷 P1111 修复公路 Label:并查集

tg2015 信息传递 (洛谷p2661)