信息传递 vijos1979 NOIP2015D1T2 强连通分量 tarjan模版题

这道题是一个裸的强连通分量的题(最短路也可以解这道题)

把每个同学看成一个点,信息的传递就是在他们之间连有向边,游戏最小轮数就是求最小环。

用强连通分量做,有一个坑点,就是当某个联通分量的大小为1的时候,不能把它算作答案(我因为这个点被坑了,WA到怀疑人生) 

我们不用记录强连通的并查集,我们只记录所有分量的大小即可。剩下的就是tarjan的事情了。

附上AC代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<iostream>
using namespace std;
template<class T> inline void read(T &_a){
    bool f=0;int _ch=getchar();_a=0;
    while(_ch<'0' || _ch>'9'){if(_ch=='-')f=1;_ch=getchar();}
    while(_ch>='0' && _ch<='9'){_a=(_a<<1)+(_a<<3)+_ch-'0';_ch=getchar();}
    if(f)_a=-_a;
}

const int maxn=200001;
int n,egcnt,head[maxn],dfn[maxn],low[maxn],idx,stk[maxn],stkcnt,sz[maxn],becnt;
bool ins[maxn];
struct edge
{
    int to,next;
}w[maxn];

void tarjan(int u)
{
    dfn[u]=low[u]=++idx;
    stk[++stkcnt]=u;
    ins[u]=true;
    for (register int i=head[u];i;i=w[i].next)
    {
        if(!dfn[w[i].to])
        {
            tarjan(w[i].to);
            low[u]=min(low[u],low[w[i].to]);
        } else if(ins[w[i].to]) low[u]=min(low[u],dfn[w[i].to]);
    }
    if(dfn[u]==low[u])
    {
        ++becnt;
        while(stk[stkcnt]!=u)
        {
            ins[stk[stkcnt]]=false;
            --stkcnt;
            ++sz[becnt];
        }
        ins[u]=false;
        --stkcnt;
        ++sz[becnt];
    }
}

inline void addedge(int from,int to)
{
    w[++egcnt].to=to;
    w[egcnt].next=head[from];
    head[from]=egcnt;
}

int main()
{
    read(n);
    for (register int i=1,a;i<=n;++i) read(a),addedge(i,a);
    for (register int i=1;i<=n;++i) if(!dfn[i]) tarjan(i);
    int ans=0x7fffffff;
    for (register int i=1;i<=becnt;++i) if(sz[i]!=1) ans=min(ans,sz[i]);
    printf("%d",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/jaywang/p/7750988.html