码迷,mamicode.com
首页 > 其他好文 > 详细

信息传递

时间:2020-03-13 18:59:34      阅读:65      评论:0      收藏:0      [点我收藏+]

标签:--   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;
}
View Code

法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 Code

 

信息传递

标签:--   view   rev   mic   preview   display   ensp   for   href   

原文地址:https://www.cnblogs.com/iss-ue/p/12487886.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!