今天的第二道tarjan:受欢迎的牛

原题来自:USACO 2003 Fall

题目描述

每头奶牛都梦想成为牛棚里的明星。被所有奶牛喜欢的奶牛就是一头明星奶牛。所有奶牛都是自恋狂,每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果 AAA 喜欢 BBB,BBB 喜欢 CCC,那么 AAA 也喜欢 CCC。牛栏里共有 NNN 头奶牛,给定一些奶牛之间的爱慕关系,请你算出有多少头奶牛可以当明星。

输入格式

第一行:两个用空格分开的整数:NNN 和 MMM。

接下来 MMM 行:每行两个用空格分开的整数:AAA 和 BBB,表示 AAA 喜欢 BBB。

输出格式

一行单独一个整数,表示明星奶牛的数量。

输入输出样例

输入 #1
3 3
1 2
2 1
2 3
输出 #1
1

说明/提示

只有 3 号奶牛可以做明星。

数据范围

题解

emmmm

这是一到极为经典的,似乎是这一类题的模板的题目:缩点
缩点,也是tarjan的极大的一个作用。
缩点只对强联通分量有用,因为强联通分量中的点可以互相到达,可以被视为一个点。

这题,是肯定是有环的。
那么肯定是很不好去实现遍历的。
怎么办呢?
根据常识,环上的点肯定都在同一个强联通分量中。
强联通分量 -->缩点
经过缩点的图,一定是一个有向无环图
那么只需要一个dfs就好了啊awa
简单题
awa
淦,题解写完了,代码还没写。。。

等等我写完代码awa

#include<bits/stdc++.h>
#define ll long long
using namespace std;
struct edge
{
    int next,to;
}e[1000001];
int head[1000001],n,m,w[1000001],tot,ccs,dfsc,low[1000001],dfn[1000001],color[10000001],cnt[1000001],de[1000001],all[1000001];bool vis[1000001];
stack<int> stk;
inline ll read()
{
    char c=getchar();ll a=0,b=1;
    for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
    for(;c>='0'&&c<='9';c=getchar())a=a*10+c-48;
    return a*b;
}
void add(int i,int j)
{
    e[++tot].next=head[i];
    e[tot].to=j;
    head[i]=tot;
}
void tarjan(int x,int fa)
{
    dfn[x]=low[x]=++dfsc;
    vis[x]=true;stk.push(x);
    for(int i=head[x];i!=0;i=e[i].next)
    {
        int u=e[i].to;
//        if(u==fa)continue;
        if(dfn[u]==0)
        {
            tarjan(u,x);
            low[x]=min(low[x],low[u]);
        }
        else
        if(vis[u]==true)
        {
            low[x]=min(low[x],dfn[u]);
        }
    }
    if(dfn[x]==low[x])
    {
        int k;
        ccs++;
        do
        {
            k=stk.top();
            stk.pop();
            color[k]=ccs;
            cnt[ccs]++;all[ccs]++;
            vis[k]=false;
        }
        while(x!=k);
    }
}
int main()
{
//    freopen(".in","r",stdin);
//    freopen(".out","w",stdout);
    n=read();m=read();
    for(int i=1;i<=m;i++)
    {
        int x=read();int y=read();
        add(x,y);
    }
    for(int i=1;i<=n;i++)
    {
        if(dfn[i]==0)
        {
            tarjan(i,-1);
        }
    }
//    for(int i=1;i<=n;i++)
//    {
//        cout<<color[i]<<endl;
//    }
    for(int i=1;i<=n;i++)
    {
        int x=i;
        for(int j=head[x];j!=0;j=e[j].next) 
        {
            int u=e[j].to;
            if(color[u]!=color[x])
            {
                de[color[i]]++;
            }
        }
    }
    int ans=0,sum=0;bool tt=0;
    for(int i=1;i<=ccs;i++)
    {
        if(de[i]==0)
        {
            ans+=cnt[color[i]];
            sum++;
            if(tt){puts("0");return 0;}
            tt=i;
        }
    }
    cout<<all[tt]<<endl;
    return 0;
}

 n年前的草稿总算是发布了awa

原文地址:https://www.cnblogs.com/HLZZPawa/p/12804826.html