有向圖強連通分量-poj-2186-Popular Cows




題意:有些牛有自己的偶像,偶像的偶像也是自己的偶像,問存在多少牛被所有牛崇拜。


題解:牛a崇拜牛b就連一條a指向b的邊,然後找出所有的強連通分量(即這個分量裏的每個點都可以到達分量中的任意一個點)。判斷有沒有出度爲0的強連通分量,而且這個點只有一個,如果有,那麼答案就是這個強連通分量裏面點的個數。

順便可以把這個作爲強連通分量的模板。


先放一個tarjan 強連通分量模板

struct recordtime
{
    int index,low;
}tour[SIZE_N];
stack<int>sta;
int vernum,edgnum,Dindex,
    scc;
int used[SIZE_N],instack[SIZE_N],
    belong[SIZE_N],num[SIZE_M];

void inittarjan()
{
    Dindex=0;
    scc=0;
    memset(used,-1,sizeof(used));
    memset(instack,0,sizeof(instack));

    memset(belong,0,sizeof(belong));
    memset(num,0,sizeof(num));
}
void tarjan(int x)
{
    int w,u;
    used[x]=1;
    tour[x].index=Dindex;
    tour[x].low=Dindex;

    Dindex++;

    sta.push(x);
    instack[x]=1;

    for(int an=head[x];an!=-1;an=pra[an].next)
    {
        u=pra[an].to;
        if(used[u]==-1)
        {
            tarjan(u);
            tour[x].low=min(tour[x].low,tour[u].low);
        }
        else
        {
            //查找棧中的元素
            if(instack[u]==1)
                tour[x].low=min(tour[x].low,tour[u].index);
        }
    }
    if(tour[x].low==tour[x].index)
    {
        scc++;
        do
        {
            w=sta.top();
            sta.pop();
            instack[w]=0;
            belong[w]=scc;
            num[scc]++;
            //printf("%d ",w);
        }while(w!=x);
        //printf("\n");
    }
}

再放一個已經ac的完整代碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#define SIZE_N 10100
#define SIZE_M 50100
using namespace std;
struct peck
{
    int to,next;
}pra[SIZE_M];


int e,outnum,ang;
int head[SIZE_N],out[SIZE_N];
void init()
{
    e=0;
    memset(head,-1,sizeof(head));
    outnum=0;
    ang=0;
    memset(out,0,sizeof(out));
}

void addedge(int x,int y)
{
    pra[e].to=y;
    pra[e].next=head[x];
    head[x]=e++;
}



struct recordtime
{
    int index,low;
}tour[SIZE_N];
stack<int>sta;
int vernum,edgnum,Dindex,
    scc;
int used[SIZE_N],instack[SIZE_N],
    belong[SIZE_N],num[SIZE_M];

void inittarjan()
{
    Dindex=0;
    scc=0;
    memset(used,-1,sizeof(used));
    memset(instack,0,sizeof(instack));

    memset(belong,0,sizeof(belong));
    memset(num,0,sizeof(num));
}
void tarjan(int x)
{
    int w,u;
    used[x]=1;
    tour[x].index=Dindex;
    tour[x].low=Dindex;

    Dindex++;

    sta.push(x);
    instack[x]=1;

    for(int an=head[x];an!=-1;an=pra[an].next)
    {
        u=pra[an].to;
        if(used[u]==-1)
        {
            tarjan(u);
            tour[x].low=min(tour[x].low,tour[u].low);
        }
        else
        {
            //查找棧中的元素
            if(instack[u]==1)
                tour[x].low=min(tour[x].low,tour[u].index);
        }
    }
    if(tour[x].low==tour[x].index)
    {
        scc++;
        do
        {
            w=sta.top();
            sta.pop();
            instack[w]=0;
            belong[w]=scc;
            num[scc]++;
            //printf("%d ",w);
        }while(w!=x);
        //printf("\n");
    }
}

void pri()
{
    for(int i=1;i<=vernum;i++)
    {
        printf("the %d th     ",i);
        for(int an=head[i];an!=-1;an=pra[an].next)
            printf("%d ",pra[an].to);
        printf("\n");
    }
}

int main()
{
    int compact,burgeon;
    //存圖
    while(scanf("%d %d",&vernum,&edgnum)!=EOF)
    {
        init();
        inittarjan();
        for (int i = 1;i<=edgnum;i++)
        {
            scanf("%d %d",&compact,&burgeon);
            addedge(compact,burgeon);
        }
        //pri();
        for (int i = 1;i<=vernum;i++)
        {
            if(used[i]==-1)
                tarjan(i);
        }
        for (int i = 1;i<=vernum;i++)
        {
            for(int an=head[i];an!=-1;an=pra[an].next)
            {
                int u=pra[an].to;
                int verbe=belong[i];
                int tobe=belong[u];
                if(verbe!=tobe){
                    out[verbe]=1;//出度不爲0
                    //printf("dengyuyi%d\n",u);
                }
            }
        }

        for (int i = 1;i<=scc;i++)//這裏i是<=強連通分量的組數
        {
            //printf("out[%d]=%d\n",i,out[i]);
            if(out[i]==0)
            {
                outnum++;
                ang=i;
            }//printf("%d\n",ang);
        }
        if(outnum!=1)//如果出度不爲0的強連通分量有兩個  那說明並不是被所有牛崇拜
            num[ang]=0;
        printf("%d\n",num[ang]);
    }
    return 0;
}


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