题解 P2341 【[HAOI2006]受欢迎的牛】

· · 题解

这题的思路是tarjan求强联通分量

题意为对于一张有向图,找出一些点,使得所有点均能到达该点,求出这些点的数量

首先我们求出所有强联通分量

显然,若1能到达2,(2,3,4)是一个强联通分量,

那么1肯定能到达2,3,4所有点。

于是我们可以将此题简化成:

找出一个强联通分量,使得所有强联通分量均能到达强联通分量,求出此强联通分量的元素个数

易证明只有一个强联通分量满足要求

那么满足条件的分量是哪个呢?其实这不需要用搜索

只要满足入度为0的强联通分量不超过1,那么tarjan求得最远的强联通分量就是所求解

以下是代码:

#include<iostream>
#include<cstdio>
using namespace std;
int i,j,k,m,n;
int top=0,cnt=0,num=0;
int First[100001],Next[100001],Last[100001],a[100001],pe[100001],pupuvovovovo[100001];
bool b[100001],b2[100001];
int q[100001],dfn[100001],low[100001],fa[100001];
void add(int x,int y)
{
    k++;a[k]=y;
    if(First[x]==0)First[x]=k;
    else Next[Last[x]]=k;
    Last[x]=k;
}
void tarjan(int x)
{
    top++;cnt++;
    dfn[x]=low[x]=cnt;
    q[top]=x;
    b[x]=true;
    int t=First[x];
    while(t!=0)
    {
        int v=a[t];
        if(dfn[v]==0)
        {
            tarjan(v);
            if(low[v]<low[x])
            low[x]=low[v];
        }
        else if(b[v]&&dfn[v]<low[x])
        low[x]=dfn[v];
        t=Next[t];
    }
    if(dfn[x]==low[x])
    {
        n++;
        while(q[top+1]!=x)
        {
            pe[n]++;
            fa[q[top]]=n;
            b[q[top]]=false;
            top--;
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    int x,y;
    k=0;
    for(i=1;i<=m;i++)
    {
        scanf("%d %d",&x,&y);
        add(x,y);
    }
    int m=n+1;
    for(i=1;i<=m-1;i++)
    {
        if(dfn[i]==0)
        tarjan(i);
    }
    for(i=1;i<=m-1;i++)
    {
        for(int o=First[i];o;o=Next[o])
        if(fa[i]!=fa[a[o]])
        pupuvovovovo[fa[i]]++;
    }
    int pp=0;
    for(i=m;i<=n;i++)
    if(pupuvovovovo[i]==0)pp++;
    if(pp==1)
    cout<<pe[m];
    else cout<<0;
}