洛谷 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:并查集?的主要内容,如果未能解决你的问题,请参考以下文章