POJ 2186

  这是一道Tarjan算法求强连通分量的题。方法是将强连通分量缩为一个点集,找出出度为0的点(或点集),值得注意的是,答案是存在于1个点集之内,如果存在两个点集合,那么它们就是互相可达的,于是又属于一个强连通分量,所以也应该缩为一个点集。

  由于数据量比较大,内存有限制,所以使用邻接表而不是邻接矩阵。由于以前觉得邻接矩阵比邻接表好写,所以对于邻接表只是略微的了解了一下,这次是第一次写邻接表,所以走了许多弯路:在节点的遍历上,我专门写了一个函数来判断两个节点之间有没有路,由于tarjan函数和求出度的时候都会用到,所以大量的函数调用造成了TLE;对于head数组,开始开的是一维,所以又写了一个函数来找到表尾,后来决定用空间换时间,多开一维,存下邻接表的末尾的节点。

#include<stdio.h>
#include<string.h>
#include<stdbool.h>

#define MAX_COW 10010

struct node
{
    int vertex;
    int next;
}edge[MAX_COW*4];

void tarjan(int,int),add(int,int);
inline int get_min(int,int);

bool instack[MAX_COW];
int dfn[MAX_COW],stack[MAX_COW],belong[MAX_COW],out[MAX_COW],containNum[MAX_COW]; 
int low[MAX_COW],head[2][MAX_COW];
int indx=0,set=0,top=0,cntVertex=0;

int main()
{
    int m,n;
    while(scanf("%d%d",&n,&m)!=EOF)
    {

        int i;
        for(i=0;i<=n;i++)
        {
            head[0][i]=head[1][i]=0;
            out[i]=containNum[i]=0;
            dfn[i]=-1;
        }
        indx=top=0;
        cntVertex=set=1;

        for(i=0;i<m;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            add(a,b);
        }

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

        int j;
        for(i=1;i<=n;i++)
        {
            j=head[0][i];
            while(j!=0)
            {
                int now=edge[j].vertex;
                if(belong[i]!=belong[now])
                {
                    out[belong[i]]++;
                }
                j=edge[j].next;
            }
        }

        int ans=0,flag=0;
        for(i=1;i<set;i++)
        {
            if(out[i]==0)
            {
                ans+=containNum[i];
                flag++;
                if(flag>1)
                    break;
            }
        }
        if(flag>1)
            printf("0\n");
        else
            printf("%d\n",ans);
    }
    return 0;
}

void tarjan(int dest,int n)
{
    dfn[dest]=low[dest]=indx++;
    stack[top++]=dest;
    instack[dest]=1;

    int i=head[0][dest];
    while(i!=0)
    {
        int now=edge[i].vertex;
            if(dfn[now]==-1)
            {
                tarjan(now,n);
                low[dest]=get_min(low[dest],low[now]);
            }
            else if(instack[now])
            {
                low[dest]=get_min(low[dest],dfn[now]);
            }
        i=edge[i].next;
    }

    if(low[dest]==dfn[dest])
    {
        while(1)
        {
            int nowNode=stack[--top];
            belong[nowNode]=set;
            containNum[set]++;
            instack[nowNode]=0;
            if(nowNode==dest)
                break;
        }
        set++;
    }
}

inline int get_min(int x,int y)
{
    return x<y?x:y;
}

void add(int from,int to)
{
    struct node tmp={to,0};
    if(head[1][from]==0)
    {
        head[0][from]=cntVertex;
        head[1][from]=cntVertex;
        edge[cntVertex++]=tmp;
        return ;
    }
    else
    {
        int dest=head[1][from];
        edge[dest].next=cntVertex;
        head[1][from]=cntVertex;
        edge[cntVertex++]=tmp;
    }
}
posted @ 2012-08-21 14:59  等待电子的砹  阅读(552)  评论(0编辑  收藏  举报