【bzoj1051】【HAOI2006】【受欢迎的牛】【强连通分量】

来源:互联网 发布:淘宝教程视频完整版 编辑:程序博客网 时间:2024/05/03 20:41

题目大意

给出一幅有向图,求所有点都能到达它的点的个数。

题解

tarjan缩点,看是否只有一个连通块,输出出度为零的连通块的大小。

其实我们不一定要真的缩点,求完强连通分量后发现这个强连通分量有出边就可以排除,最后看可行数是否大于一,并同时记录连通块的大小,判断后输出即可。

code

#include<set>#include<cmath>#include<cstdio>#include<cstring>#include<algorithm>#define fo(i,j,k) for(int i=j;i<=k;i++)#define fd(i,j,k) for(int i=j;i>=k;i--)using namespace std;int const maxn=10000,maxm=50000;int n,m,cntedge,top,cnttime,to[maxm+10],next[maxm+10],begin[maxn+10],dfn[maxn+10],low[maxn+10],    stack[maxn+10],num[maxn+10],size[maxn+10];bool instack[maxn+10],flag[maxn+10];void insert(int u,int v){    to[++cntedge]=v;    next[cntedge]=begin[u];    begin[u]=cntedge;}void tarjan(int now){    dfn[now]=low[now]=++cnttime;    instack[stack[++top]=now]=1;    for(int i=begin[now];i;i=next[i])        if(!dfn[to[i]]){            tarjan(to[i]);            low[now]=min(low[now],low[to[i]]);        }        else if(instack[to[i]])low[now]=min(low[now],dfn[to[i]]);    if(dfn[now]==low[now]){        while(stack[top]!=now){            size[now]+=size[num[stack[top]]];            num[stack[top]]=now;            instack[stack[top--]]=0;        }        num[stack[top]]=now;        instack[stack[top--]]=0;    }}int main(){    freopen("d.in","r",stdin);    freopen("d.out","w",stdout);    scanf("%d%d",&n,&m);    fo(i,1,m){        int a,b;scanf("%d%d",&a,&b);        insert(a,b);    }    fo(i,1,n)num[i]=i,size[i]=1;    fo(i,1,n)        if(!dfn[i])tarjan(i);    fo(i,1,n)flag[num[i]]=1;    fo(i,1,n)        for(int j=begin[i];j;j=next[j])            if(num[i]!=num[to[j]])flag[num[i]]=0;    int cnt=0,ans=0;    fo(i,1,n)        if(flag[i]){            cnt++;            ans+=size[i];        }    if(cnt==1)printf("%d",ans);    else printf("0");    return 0;}
0 0
原创粉丝点击