POJ 2186 Popular Cows(初学强连通)

题意:有n个牛,m个有向“仰慕”关系,关系可传递,求多少个牛被所有牛都“仰慕”

思路:显然被所有牛仰慕的牛群是一强连通分量

所以先把乱图缩点成有向无环图


对有向无环图有这个重要结论:

任何连通的图都至少有一个入度为0的点和至少有一个出度为0的点(也就是至少有一个最高强连通分量和一个最低强连通分量)


所以本题是找连通图的唯一的最低强连通分量,显然仅有一个出度为0的强连通分量即是解


Tarjan算法:

//832K	79MS
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

const int N= 1e4+5;
const int M= 5e4+50;
struct edge
{
    int u,v;
    int next;
}es[M];
int head[N];
int low[N],dfn[N],tmp[N];
int n,m;
int col[N];
int sta[N];
int top;
int scc_num;
void tardfs(int u,int lay)
{
    tmp[u]=1;
    low[u]=lay;
    dfn[u]=lay;
    sta[++top]=u;
    for(int i=head[u];~i;i=es[i].next)
    {
        int v=es[i].v;
        if(tmp[v]==0) tardfs(v,lay+1);
        if(tmp[v]==1) low[u]=min(low[u],low[v]);
    }
    if(dfn[u]==low[u])
    {
        ++scc_num;
        while(1)
        {
            int x=sta[top];
            low[x]=scc_num;
            tmp[x]=2;
            if(sta[top--]==u) break;
        }
    }
}
int tarjan()
{
    for(int i=1;i<=n;i++)
        if(tmp[i]==0) tardfs(i,1);
    return scc_num;
}
void ini()
{
    memset(head,-1,sizeof(head));
    memset(tmp,0,sizeof(tmp));
    memset(col,0,sizeof(col));
    memset(low,0,sizeof(low));
    top=0;
    scc_num=0;
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        ini();
        for(int i=1;i<=m;i++)
        {
            int  u,v;
            scanf("%d%d",&u,&v);
            es[i].u=u;
            es[i].v=v;
            es[i].next=head[u];
            head[u]=i;
        }
        int num=tarjan();
        int cnt=0;
        for(int i=1;i<=m;i++)
        {
            if(low[es[i].u]==low[es[i].v]) continue;
            int u=es[i].u;
            col[low[u]] = 1;
        }
        int t,ans=0;
        for(int i=1;i<=num;i++) if(col[i]==0) cnt++,t=i;
        if(cnt!=1) puts("0");
        else
        {
            for(int i=1;i<=n;i++)
                if(low[i]==t) ans++;
            printf("%d\n",ans);
        }
    }
    return 0;
}

Garbow算法:

//856K	32MS	C++	1844B
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

const int N= 1e4+5;
const int M= 5e4+50;
struct edge
{
    int u,v;
    int next;
}es[M];
int head[N];
int dfn[N];
int n,m;
int gro[N];
int col[N];
int sta1[N];
int sta2[N];
int tp1,tp2;
int scc_num;

void garbow(int u,int lay)
{
    dfn[u]=lay;
    sta1[++tp1]=u;
    sta2[++tp2]=u;
    for(int i=head[u];~i;i=es[i].next)
    {
        int v=es[i].v;
        if(gro[v]) continue;
        if(!dfn[v]) garbow(v,lay+1);
        else while(dfn[sta1[tp1]]>dfn[v]) tp1--;
    }

    if(sta1[tp1]==u)
    {
        tp1--;
        scc_num++;
        while(1)
        {
            int v=sta2[tp2];
            gro[v]=scc_num;
            if(sta2[tp2--]==u) break;
        }
    }

}
void ini()
{
    memset(head,-1,sizeof(head));
    memset(col,0,sizeof(col));
    memset(gro,0,sizeof(gro));
    tp1=tp2=scc_num=0;
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        ini();
        for(int i=1;i<=m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            es[i].u=u;
            es[i].v=v;
            es[i].next=head[u];
            head[u]=i;
        }

        for(int i=1;i<=n;i++) if(!dfn[i]) garbow(i,1);

        for(int i=1;i<=m;i++)
        {
            int u=es[i].u,v=es[i].v;
            if(gro[u]==gro[v])  continue;
            col[gro[u]]=1;
        }

        int cnt=0,t;
        for(int i=1;i<=scc_num;i++) if(col[i]==0) cnt++,t=i;
        if(cnt!=1) puts("0");
        else
        {
            int ans=0;
            for(int i=1;i<=n;i++) if(gro[i]==t) ans++;
            printf("%d\n",ans);
        }
    }
    return 0;
}


你可能感兴趣的:(POJ 2186 Popular Cows(初学强连通))