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
*/


 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章