强联通分量 缩点 tarjan算法

来源:互联网 发布:百度验证码算法 编辑:程序博客网 时间:2024/05/16 07:53
/*做一遍DFS,用dfn[i]表示编号为i的节点在DFS过程中的访问序号(也可以叫做开始时间)用low[i]表示i节点DFS过程中i的下方节点所能到达的开始时间最早的节点的开始时间。初始时dfn[i]=low[i]在DFS过程中会形成一搜索树。在搜索树上越先遍历到的节点,显然dfn的值就越小。DFS过程中,碰到哪个节点,就将哪个节点入栈。栈中节点只有在其所属的强连通分量已经全部求出时,才会出栈。如果发现某节点u有边连到搜索树中栈里的节点v,则更新u的low 值为dfn[v](更新为low[v]也可以)。如果一个节点u已经DFS访问结束,而且此时其low值等于dfn值,则说明u可达的所有节点,都不能到达任何在u之前被DFS访问的节点 ---- 那么该节点u就是一个强连通分量在DFS搜索树中的根。此时将栈中所有节点弹出,包括u,就找到了一个强连通分量*//*本体题意: *有N(N<=10000)头牛,每头牛都想成为most poluler的牛;  *给出M(M<=50000)个关系,如(1,2)代表1欢迎2,关系可以传递,但是不可以相互,即1欢迎2不代表2欢迎1;  *但是如果2也欢迎3那么1也欢迎3;  *给出N,M和M个欢迎关系,求被所有牛都欢迎的牛的数量; *求出强联通分量后,所以解题的方法就应该是在缩点之后的图G中求出所有出度为零的点的个数,如果个数大于1, 说明至少存在两个分量之间的牛不会相互YM,明显和题目要求不符合,输出0,如果等于1则说明只有一个强连通分 量里面的牛被其他全部的牛YM,那么答案就是这个分量中点的个数 */#include <cstdio>#include <string.h>#include <iostream>#include <algorithm>#include <vector>#define N 50010using namespace std;int dfs[N],instack[N],low[N],out[N],belong[N];int stack[N];int deep,top,cnt,n,m;vector<int> map[N];int min(int a,int b){    return a>b?b:a;}void tarjan(int k){    int i,j;    dfs[k]=low[k]=++deep;    stack[++top]=k;    instack[k]=1;    for(i=0; i<map[k].size(); i++)    {        j=map[k][i];        if(dfs[j]==0)        {            tarjan(j);            low[k]=min(low[k],low[j]);        }        else        if(instack[j])        {            low[k]=min(low[k],dfs[j]);        }    }    if(low[k]==dfs[k])    {        cnt++;        do        {            j=stack[top--];            belong[j]=cnt;            instack[j]=0;        }        while(j!=k);    }}int main(){    int i,j,a,b,ans,num,pos;    while(scanf("%d%d",&n,&m)!=EOF)    {    memset(dfs,0,sizeof(dfs));    memset(instack,0,sizeof(instack));    memset(low,0,sizeof(low));    memset(out,0,sizeof(out));    memset(belong,0,sizeof(belong));    memset(stack,0,sizeof(stack));    memset(map,0,sizeof(map));    deep=top=cnt=0;        for(i=1; i<=m; i++)        {            scanf("%d%d",&a,&b);            map[a].push_back(b);        }        for(i=1; i<=n; i++)            if(dfs[i]==0)                tarjan(i);        if(cnt==1)        {        printf("%d\n",n);        continue;        }        for(i=1; i<=n; i++)            for(j=0; j<map[i].size(); j++)                if(belong[i]!=belong[map[i][j]])                {                    out[belong[i]]++;                }        ans=pos=num=0;        for(i=1; i<=cnt; i++)            if(!out[i])            {                num++;                pos=i;            }        if(num==1)        {            for(j=1; j<=n; j++)                if(belong[j]==pos)                {                    ans++;                }            printf("%d\n",ans);        }        else printf("0\n");    }    return 0;}

0 0
原创粉丝点击