信息传递 NOIP2015 day1 T2

题文:

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

这题目看上去是在找一个有向图的最小环,因为每个点只有一个出度,所以图中不可能出现强连通分量中套着

强连通分量的情况,所以我们只要跑遍tarjian,统计每个分量的size就可以了;

但是n平方的算法为啥没T掉,求解;

AC代码:

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<cstring>
#include<stack>
#include<algorithm> 
using namespace std;
const int MAXN=2000020;
int n,num=0,num1=0;
int dfn[MAXN],low[MAXN];
bool in[MAXN];
int ans=1<<30;
struct edge{
    int first;
    int next;
    int quan;
    int to;
}a[MAXN];
void addedge(int from,int to){
    a[++num].to=to;
    a[num].next=a[from].first;
    a[num].quan=1;
    a[from].first=num;
}
stack<int> q;
void tarjian(int now){
    dfn[now]=low[now]=num1++;
    in[now]=1;
    q.push(now);
    for(int i=a[now].first;i;i=a[i].next){
        int to=a[i].to;
        if(!dfn[to]){
            tarjian(to);
            low[now]=min(low[now],low[to]);
        }
        else if(in[to]){
            low[now]=min(low[now],dfn[to]);
        }
    }
    if(low[now]==dfn[now]){
        int u=-1,size=0;
        while(u!=now){
            u=q.top();
            q.pop();
            in[u]=0;
            size++;
        }
        if(size!=1)
        ans=min(ans,size);
    }
}
int main()
{
    memset(in,0,sizeof(in));
    while(!q.empty()) q.pop();
    cin>>n;
    for(int i=1;i<=n;i++){
        int x;
        scanf("%d",&x);
        addedge(i,x);
    }
    for(int i=1;i<=n;i++){
        if(!dfn[i]){
            tarjian(i);
        }    
    }
    printf("%d",ans);
}
原文地址:https://www.cnblogs.com/renjianshige/p/7003654.html