标签:-- view rev mic preview display ensp for href
题面:https://www.acwing.com/problem/content/519/
有 n 个同学(编号为 1 到 n)正在玩一个信息传递的游戏。
在游戏里每人都有一个固定的信息传递对象,其中,编号为 i 的同学的信息传递对象是编号为 TiTi 的同学。
游戏开始时,每人都只知道自己的生日。
之后每一轮中,所有人会同时将自己当前所知的生日信息告诉各自的信息传递对象(注意:可能有人可以从若干人那里获取信息,但是每人只会把信息告诉一个人,即自己的信息传递对象)。
当有人从别人口中得知自己的生日时,游戏结束。
请问该游戏一共可以进行几轮?
题目意思很清楚,就是求最小环。先看样例
法1 :拓扑+电风扇(dfs)
很容易发现最小环是2->4->3->2
并且1和5不在环内。
观察到5没有前驱,而且经过拓扑之后1也是如此,图中就只剩下环
我们就从头到尾扫一遍。没有前驱就一定在环内,从这个点开始dfs遍历环内的点并标记
然后用环的大小更新答案
#include <bits/stdc++.h> using namespace std; const int maxn=2000009; int indug[maxn],fa[maxn],vis[maxn],n; queue<int>q; void tuopu() { for(int i=1;i<=n;i++) if(indug[i]==0) q.push(i); while(!q.empty()) { int ans=q.front();q.pop(); if(--indug[fa[ans]]==0) q.push(fa[ans]); } } int ans=99999999; void dfs(int now,int qi,int s) { if(fa[now]==qi){ ans=min(ans,s); return; } if(vis[fa[now]]) return; vis[fa[now]]=1; dfs(fa[now],qi,s+1); } int main() { cin>>n; for(int i=1;i<=n;i++) { int x; cin>>x; indug[x]++; fa[i]=x; } tuopu(); for(int i=1;i<=n;i++) { if(vis[i]) continue; if(indug[i]==0) continue; vis[i]=1; dfs(i,i,0); } cout<<ans+1; }
法2:拓扑+并查集
核心思路不变,仍然是一遍拓扑去掉不在环内的点
然后对于其余的点找祖先,把祖先的计数器加加
显然,环内的每一个点都会让祖先加1
最后扫一遍计数器不为0的点,取最小值
#include <iostream> #include <algorithm> #include <cstring> #include <string.h> #include <math.h> #include <queue> #include <map> #include <stack> #include <vector> using namespace std; int n; int indug[200009]; int vis[200009]; vector<int>vec[200009]; void tuopu() { queue<int>d; for(int i=1;i<=n;i++) if(indug[i]==0) vis[i]=1,d.push(i); while(!d.empty()) { int ans=d.front(); d.pop(); for(int i=0;i<vec[ans].size();i++) { if(--indug[vec[ans][i]]==0) vis[vec[ans][i]]=1,d.push(vec[ans][i]); } } } int num[200009],pre[200009]; int cnt[200009]; int find(int x) { if(pre[x]!=x) pre[x]=find(pre[x]); return pre[x]; } void join(int q,int w) { pre[find(q)]=find(w); return; } int main() { cin>>n; for(int i=1;i<=n;i++) pre[i]=i; for(int i=1;i<=n;i++) { int l;cin>>l; vec[i].push_back(l); indug[l]++; join(i,l); } tuopu(); for(int i=1;i<=n;i++) { if(vis[i]==0) cnt[find(i)]++; } int ans=999999; for(int i=1;i<=n;i++) if(cnt[i]!=0) ans=min(ans,cnt[i]); cout<<ans; }
标签:-- view rev mic preview display ensp for href
原文地址:https://www.cnblogs.com/iss-ue/p/12487886.html