[Tarjan]BZOJ 1051—— [HAOI2006]受欢迎的牛

来源:互联网 发布:一号防线监控网络设置 编辑:程序博客网 时间:2024/06/03 03:37

[Tarjan]BZOJ 1051—— [HAOI2006]受欢迎的牛

题目梗概

给出A喜欢B的关系,这个关系可以传递。

求被所有牛喜欢的牛的数量。

解题思路

缩点之后,出度为0的强连通分量的大小就是答案。

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxm=50005,maxn=10005;int lnk[maxn],son[maxm],nxt[maxm],stack[maxn],dnf[maxn],low[maxn],id[maxn],ans,tot,t,top,h,f[maxn];inline int _read(){    int num=0;char ch=getchar();    while (ch<'0'||ch>'9') ch=getchar();    while (ch>='0'&&ch<='9') num=num*10+ch-48,ch=getchar();    return num;}bool vis[maxn],b[maxn][maxn];void add(int x,int y){    nxt[++tot]=lnk[x];lnk[x]=tot;son[tot]=y;}void tarjan(int x){    dnf[x]=low[x]=++t;    vis[x]=1;stack[++top]=x;    for (int j=lnk[x];j;j=nxt[j])    if (dnf[son[j]]==0){tarjan(son[j]);low[x]=min(low[x],low[son[j]]);}    else if (vis[son[j]]) low[x]=min(low[x],dnf[son[j]]);    if (dnf[x]==low[x]){        vis[x]=0;id[x]=++h;        while (stack[top]!=x){            id[stack[top]]=h;            vis[stack[top--]]=0;        }        top--;    }}int main(){    freopen("exam.in","r",stdin);    freopen("exam.out","w",stdout);    int n=_read(),m=_read();    for (int i=1;i<=m;i++){        int x=_read(),y=_read();        add(x,y);    }    for (int i=1;i<=n;i++) if (dnf[i]==0) tarjan(i);    for (int i=1;i<=n;i++)    for (int j=lnk[i];j;j=nxt[j])    if (id[i]!=id[son[j]]) f[id[i]]=1;    for (int i=1;i<=n;i++)    if (!f[id[i]]) ans++;    printf("%d\n",ans);    return 0;}