poj 2186 tarjian与gabow算法

Popular Cows
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 18198   Accepted: 7330

Description

Every cow's dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you are given up to M (1 <= M <= 50,000) ordered pairs of the form (A, B) that tell you that cow A thinks that cow B is popular. Since popularity is transitive, if A thinks B is popular and B thinks C is popular, then A will also think that C is
popular, even if this is not explicitly specified by an ordered pair in the input. Your task is to compute the number of cows that are considered popular by every other cow.

Input

* Line 1: Two space-separated integers, N and M

* Lines 2..1+M: Two space-separated numbers A and B, meaning that A thinks B is popular.

Output

* Line 1: A single integer that is the number of cows who are considered popular by every other cow.

Sample Input

3 3
1 2
2 1
2 3

Sample Output

1
题意:问那个牛最受欢迎。即问有多少个点其他任何点都能到达。单向连通。
思路:强连通缩点。求出度为零的点(强连通分量),这个点只能有一个,输出这个强连通分量重点的个数,否则输出0。
tarjian算法与gabow算法,二者的思想是相同的,只是一个用数组存,一个是用的栈来维护的那个追溯到的父节点。据说:Galow算法更省时。
tarjian算法代码:
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<vector>
using namespace std;
#define max_n 10005
#define max_e 250002
#define inf 99999999

int stack[max_n],top;//栈
int isInStack[max_n];//是否在栈内
int low[max_n],dfn[max_n],tim;//点的low,dfn值;time从1开始
int node_id;//强连通分量的个数
int head[max_n],s_edge;//邻接表头  s_edge从1开始
int gro_id[max_n];//记录某个点属于哪个强连通分量
int n,m;
int in[max_n],out[max_n];//出度与入度

vector<int> vec[max_n];//边的后节点存储

struct Node
{
    int to;
    int next;
} edge[max_e];
void init()//初始化
{
    s_edge=0;//存储
    memset(head,0,sizeof(head));
    memset(edge,0,sizeof(edge));

    top=0;//tarjian初始化
    tim=0;
    node_id=0;
    memset(isInStack,0,sizeof(isInStack));
    memset(low,0,sizeof(low));
    memset(dfn,0,sizeof(dfn));


    memset(in,0,sizeof(in));//出度入度的初始化
    memset(out,0,sizeof(out));


}
void addedge(int u,int v)
{
    s_edge++;
    edge[s_edge].to=v;
    edge[s_edge].next=head[u];
    head[u]=s_edge;
}
int min(int a,int b)
{
    if(a<b)return a;
    else return b;
}
void tarjan(int u)
{
    //low值为u或u的子树能够追溯到得最早的栈中节点的次序号
    stack[top++]=u;
    isInStack[u]=1;
    dfn[u]=++tim; //记录点u出现的记录,并放在栈中
    low[u]=tim;

    int e,v;
    for(e=head[u]; e; e=edge[e].next) //如果是叶子节点,head[u]=0,edge[e].next=0;
    {
        v=edge[e].to;
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(isInStack[v])
            low[u]=min(low[u],dfn[v]);
    }
    int j;
    if(dfn[u]==low[u])//找到一个强连通,元素出栈
    {
        node_id++;
        while(j=stack[--top])
        {
            isInStack[j]=0;
            gro_id[j]=node_id;
            if(j==u)break;
        }
    }
}
void find()//tarjian寻找
{
    for(int i = 1 ; i <=n ; ++i)
    {
        if(!dfn[i])
        {
            tarjan(i);
        }
    }
}

int main()
{
    int a,b;
    while(scanf("%d %d",&n,&m)!=EOF)
    {
        init();
        for(int i=1; i<=n; i++)
        vec[i].clear();
        for(int i = 0 ; i <m ; ++i)
        {
            scanf("%d%d",&a,&b);
            vec[a].push_back(b);
            addedge(a,b);
        }
        find();
        int sum=0,sum1=0;
        for(int i=1; i<=n; i++)
        {
            for(int j=0; j<vec[i].size(); j++)//求强连通分量的出、入度
            {
                if(gro_id[i]!=gro_id[vec[i][j]])
                {
                    out[gro_id[i]]++;
                    //in[gro_id[vec[i][j]]]++;
                }
            }
        }
        int ans=0;
        for(int i=1; i<=node_id; i++)
        {
            if(out[i]==0)
            {
                sum++;
                for(int j=1;j<=n;j++)
                if(gro_id[j]==i)
                sum1++;
            }
            if(ans<sum1)
            ans=sum1;
            //if(in[i]==0)
            //sum1++;

        }
        if(sum==1)
        cout<<ans<<endl;
        else
        cout<<"0"<<endl;
    }
    return 0;
}
/*
1
3 3
1 2
2 3
3 1
*/

Gabow算法代码:

#include<iostream>
#include<string.h>
#include<stdio.h>
#include<vector>
using namespace std;
#define max_n 10005
#define max_e 250002
#define inf 99999999

int stack[max_n],stack1[max_n],top,top1;//栈

int dfn[max_n],tim;//dfn值;time从1开始
int node_id;//强连通分量的个数

int gro_id[max_n];//记录某个点属于哪个强连通分量
int n,m;
int in[max_n],out[max_n];//出度与入度

vector<int> vec[max_n];//边的后节点存储
vector<int> cvec[max_n];//存储每个强连通分量的元素

void init()//初始化
{
    top=0;//tarjian初始化
    top1=0;
    tim=0;
    node_id=0;
    memset(dfn,-1,sizeof(dfn));

    memset(in,0,sizeof(in));//出度入度的初始化
    memset(out,0,sizeof(out));

    memset(stack,-1,sizeof(stack));
    memset(stack1,-1,sizeof(stack1));
    memset(gro_id,-1,sizeof(gro_id));

}

void Gabow(int u)
{
    stack[++top]=u;
    stack1[++top1]=u;//相当于low数组
    dfn[u]=tim++; //记录点u出现的记录,并放在栈中
    int e,v;
    for(e=0; e<vec[u].size(); e++)
    {
        v=vec[u][e];
        if(dfn[v]==-1)
        {
            Gabow(v);
        }
        else if(gro_id[v]==-1)
        {
            while(dfn[stack1[top1]]>dfn[v])
            top1--;
        }
    }
    int j;
    if(stack1[top1]==u)//找到一个强连通,元素出栈
    {
        ++node_id;
        --top1;
        do
        {
            gro_id[stack[top]]=node_id;
            cvec[node_id].push_back(stack[top]);

        }while(stack[top--]!=u);
    }
}
void find()
{

    for(int i = 1 ; i <=n ; ++i)
    {
        if(dfn[i-1]==-1)
        {
            Gabow(i-1);
        }
    }
}

int main()
{
    int a,b;
    while(scanf("%d %d",&n,&m)!=EOF)
    {
        init();
        for(int i=0; i<=n; i++)
        {
            vec[i].clear();
            cvec[i].clear();
        }
        for(int i = 0 ; i <m ; ++i)
        {
            scanf("%d%d",&a,&b);
            vec[a-1].push_back(b-1);
        }
        find();
        int sum=0,sum1=0;
        for(int i=0; i<n; i++)
        {
            for(int j=0; j<vec[i].size(); j++)//求强连通分量的出、入度
            {
                if(gro_id[i]!=gro_id[vec[i][j]])
                {
                    out[gro_id[i]]++;
                    //in[gro_id[vec[i][j]]]++;
                }
            }
        }
        int ans=0;
        for(int i=1; i<=node_id; i++)
        {
            if(out[i]==0)
            {
                sum++;
                ans=cvec[i].size();
            }
        }
        if(sum==1)
        cout<<ans<<endl;
        else
        cout<<"0"<<endl;
    }
    return 0;
}
/*
3 3
1 2
2 1
2 3
*/


 

 

你可能感兴趣的:(poj 2186 tarjian与gabow算法)