【题解】洛谷P2341 [HAOI2006]受欢迎的牛(强连通分量)

洛谷P2341:https://www.luogu.org/problemnew/show/P2341

前言

这题看错题目 足足花了将近5小时提交了15次 在一位dalao的提醒下才AC了

记得要看清题意啊!

思路

可以成为明星的牛是图中唯一的出度为0的强连通分量中的所有牛

因为如果有两个或以上的话 他们之间无法互相爱慕

即可把所有互相爱慕的牛用Tarjan缩点

判断如果出度为0的强连通分量只有一个 就输出这个强连通分量中的牛数

如果有两个或以上即无解

代码

#include<iostream>
#include<cstdio>
using namespace std;
#define maxn 10010
int n,m,cnt,num,col,top,ans,pd;
int dfn[maxn],low[maxn],de[maxn],cow[maxn],f[maxn],st[maxn],h[maxn],co[maxn];
bool vis[maxn];
struct Edge
{
    int to;
    int next;
}e[maxn*5];
void add(int x,int y)
{
    e[++cnt].to=y;
    e[cnt].next=h[x];
    h[x]=cnt;
}
void Tarjan(int u)
{
    dfn[u]=low[u]=++num;
    st[++top]=u;//入栈
    vis[u]=1;//判断是否在栈中 
    for(int i=h[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(!dfn[v])
        {
            Tarjan(v);
            low[u]=min(low[u],low[v]);//low表示u与其子孙到达的最小编号 
        }
        else 
        if(vis[v])//判断v是否在栈中
        low[u]=min(low[u],dfn[v]);
        //可以改成 min(low[u],low[v])
        //因为此时v的low和dfn还未修改 
    }
    if(dfn[u]==low[u])
    {
        co[u]=++col;//属于第col个强连通分量 
        ++cow[col];//计算第col个强连通分量中有几头牛 
        while(st[top]!=u)
        {
            ++cow[col];
            co[st[top]]=col;
            vis[st[top--]]=0;
        }
        --top;
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);
    }
    for(int i=1;i<=n;i++)
    if(!dfn[i]) Tarjan(i);//缩点
    for(int i=1;i<=n;i++)//统计出度 
        for(int j=h[i];j;j=e[j].next)
            if(co[i]!=co[e[j].to])//如果不是同一个强连通分量 
            de[co[i]]++;
    for(int i=1;i<=col;i++)
    if(!de[i])
    {
        ans=cow[i];//出度为0 说明这头牛是被所有牛喜欢 
        pd++;
    }
    if(pd==1)
    printf("%d",ans);
    else
    printf("0");
}
View Code
原文地址:https://www.cnblogs.com/BrokenString/p/9688405.html