• 2661 信息传递(tarjan&拓扑)


    2015 NOIP提高组 Day1 第二题

    提交次数:3

    题目描述

    有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 个整数,表示游戏一共可以进行多少轮。

    tarjan:

    代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<vector>
     4 #include<stack>
     5 using namespace std;
     6 vector<vector<int> > v;
     7 vector<int>lt[200010];
     8 stack<int>s;
     9 int dfn[200010];
    10 int low[200010];
    11 int belong[200010];
    12 bool instack[200010]; 
    13 int bcnt;
    14 int n;
    15 int index;
    16 void tarjan(int x){
    17     dfn[x] = low[x] = ++index;
    18     s.push(x);
    19     instack[x] = true;
    20     int i;
    21     for(i = 0; i < v[x].size(); i++){
    22         int k = v[x][i];
    23         if(!dfn[k]){
    24             tarjan(k);
    25             low[x] = min(low[x], low[k]);
    26         }
    27         else if(instack[k])
    28             low[x] = min(low[x], dfn[k]);    
    29     }
    30     int k;
    31     if(dfn[x]==low[x]){
    32         bcnt++;
    33         do{
    34             k = s.top();
    35             s.pop();
    36             instack[k] = false;
    37             lt[bcnt].push_back(k);
    38         }while(k != x);
    39     }
    40 }
    41 int main(){
    42     cin>>n;
    43     int i;
    44     v.resize(n+1);
    45     for(i = 1; i <= n; i++){
    46         int x;
    47         scanf("%d", &x);
    48         v[i].push_back(x);
    49     }
    50     for(i = 1; i <= n; i++){
    51         if(!dfn[i])
    52             tarjan(i);
    53     }
    54     int ans = 1<<30;
    55     for(i = 1; i <= bcnt; i++){
    56         int x = lt[i].size();
    57         if(x > 1) ans = min(ans, x);
    58     }
    59     cout<<ans<<endl;
    60     return 0;
    61 }

    备注:

    特殊时期就长话短说了。

    没看出来这是一道求最小环的裸题,唉太差。我突然发现在之前写的tarjan求强连通分量的模板我没发在博客上,这个就当模板了。

    犯了两个错误,第一个是v忘了resize然后就炸了。另一个是误以为在同一个强连通分量的结点编号都是连着的,然后就只得了10分。

    第二次提交最后一个点超时,输入改成scanf就可以了。

    哦对,还有就是要注意,强连通分量的大小最小也得是一个以上。

    拓扑:

    代码:

    #include<iostream>
    #include<queue> 
    using namespace std;
    
    struct node{
        int next;
        int in;
        bool book;
        node(){next = in = 0; book = 0;}
    }p[200010];
    int ans = 1<<30;
    queue<node>q;
    int n;
    
    int main(){
        cin>>n;
        int i;
        for(i = 1; i <= n; i++){
            cin>>p[i].next;
            p[p[i].next].in++;
        }
        for(i = 1; i <= n; i++){
            if(!p[i].in){
                q.push(p[i]);
                p[i].book = true;
            }
        }
        while(!q.empty()){
            node k = q.front();
            q.pop();
            p[k.next].in--;
            if(p[k.next].in==0){
                q.push(p[k.next]);
                p[k.next].book = 1; 
            }
        }
        for(i = 1; i <= n; i++){
            if(!p[i].book){
                int j = i, count = 0;
                do{
                    count++;
                    p[j].book=1;
                    j = p[j].next;
                }while(j!=i);
                ans = min(ans, count);
            }
        }
        cout<<ans<<endl;
        return 0;
    }

    备注:

    “先拓扑,去掉图中不在环内的节点,再判断每个环的长度,最短的那个环的长度就是答案了!”

    第一次写拓扑,参考某题解。一个点入度为0时不可能在环内。这里判断每个环长度,然后找最短的,用到了出度1的条件,决定了每个点只能在1个环内。

  • 相关阅读:
    Python之位移操作符所带来的困惑
    SR采用PubSubHubbub协议实时接收GReaderSharedItems更新
    如何找到正在热传的微博客图片?
    手持设备:懒人的互联网音乐智能同步/播放器
    七十二般变化解得了三灾?
    如何测量Google Reader用户的分享活跃度
    基于Google Reader发展起来的个性化推荐系统之三大问题
    Python检测Windows剩余磁盘空间
    Python 内部类,内部类调用外部类属性,方法
    禁止IE页面自动跳转到EDGE浏览器的方法
  • 原文地址:https://www.cnblogs.com/fangziyuan/p/6077424.html
Copyright © 2020-2023  润新知