poj 2186 Popular Cows (Tarjan 强连通分量+压缩点)

来源:互联网 发布:win7打开本地端口 编辑:程序博客网 时间:2024/05/31 06:23


考察算法:强连通分量+压缩点。


先说明下题目的大意。

有一群牛在相互崇拜。崇拜是单向的。且崇拜是可传递的,即a->b,b->c,可以得到a->c。

分别告诉你总共有n头牛,m条彼此间的崇拜关系,让你求出有多少头牛是其他牛都崇拜的,这里称之为明星牛~~。

思路:

要求出明星牛的个数,可以很轻松的想到作为明星牛,是不能崇拜其他牛的~,但是问题来了。

然后明星牛的个数一定是1嘛?经过博主多次WR发现不是的快哭了。有一种情况就是这个明星牛群是一个有向环,有向环?肯定要想到强连通分量!他们彼此相互崇拜。

同理,整个牛群中有可能存在多个有向环。真的是搞不懂难道他们还自己崇拜自己?

到这里,这个题的大概思路就出来了。求出牛群中有多少个强连通分量,把每个强连通分量都压缩成一个点,整个一个牛群间的关系就可以转化成一个有向无环图,即为DAG。

然后找明星牛,明星牛所在的压缩点的出度一定是为零的~。

如果有多个压缩点的出度都为零了呢?我一开始没有考虑这里,又WR了好几次。当有多个压缩点的出度为零,那么很显然,整个牛群中没有明星牛!

pass:这个题的数据poj出的有点弱,好像数据里没有考虑孤立结点的情况,给一组数据,博主没有过,但是提交的时候AC了,下面的代码是改正过的代码。

这里求强连通分量我用的是trajan算法

input4 31 22 11 3/*4是孤立节点*/output0

下面是完整的代码

#include<cstdio>#include<cstring>#include<stack>using namespace std;const int vMaxsize = 10050;const int eMaxsize = 50050;typedef struct{    int s,e,next;}node;node edge[eMaxsize];int head[vMaxsize],dfn[vMaxsize],low[vMaxsize],color[vMaxsize];bool vis[vMaxsize],judge[vMaxsize];int e_num,scc,index;void addedge(int a,int b)/*加边*/{    edge[e_num].s = a;    edge[e_num].e = b;    edge[e_num].next = head[a];    head[a] = e_num++;}void getmap(int n,int m)/*建图*/{    memset(head,-1,sizeof(head));    memset(vis,false,sizeof(vis));    memset(dfn,-1,sizeof(dfn));    memset(low,0,sizeof(low));    memset(judge,false,sizeof(judge));    e_num = 0;    while(m--)    {        int a,b;        scanf("%d %d",&a,&b);        judge[a] = true;        judge[b] = true;        addedge(a,b);    }}stack<int>s;void trajan(int u)/*求强连通分量*/{    dfn[u] = low[u] = index++;    vis[u] = true;    s.push(u);    for(int i = head[u] ; i != -1 ; i = edge[i].next)    {        int v = edge[i].e;        if(dfn[v] == -1)        {            trajan(v);            if(low[u] > low[v]) low[u] = low[v];        }        else if( vis[v] && low[u] > dfn[v])        {            low[u] = dfn[v];        }    }    if(low[u] == dfn[u])    {        int j;        scc++;        do        {            j = s.top();            s.pop();            vis[j] = false;            color[j] = scc;/*不同的强连通分量染色*/        }while(u!=j);    }}void solve(int n){    scc = 0;    for(int i = 1; i <= n ; i++)    {       if(dfn[i] == -1)       {           trajan(i);       }    }}int main(){    int n,m;    while(scanf("%d %d",&n,&m)!=EOF)    {        int in[vMaxsize],out[vMaxsize];        memset(in,0,sizeof(in));        memset(out,0,sizeof(out));        getmap(n,m);        solve(n);        int key = 0;        for(int i = 1; i <= n ; i++)/*确定是否有孤立节点*/        {            if(judge[i] == false)            {                key++;            }        }        for(int i = 0 ; i < e_num ; i++)        {            if(color[edge[i].s] != color[edge[i].e])            {                out[color[edge[i].s]]+=1;/*存储各个压缩点的出度跟入度*/                in[color[edge[i].e]]+=1;            }        }        int sum = 0;        bool flag = false;        if(key != 0)/*有孤立节点,则一定没有明星牛*/        {            sum = 0;        }        else if(scc == 1)/*整个牛群只有一个强连通分量,一定是彼此相互崇拜的*/        {            sum = n;        }        else        {            for(int i = 1; i <= scc ; i++)            {                if(out[i] == 0 && in[i] != 0)                {                    for(int j = 1; j <= n ; j++)                    {                        if(color[j] == i)                        {                            sum++;                        }                    }                    if(!flag)/*标记,是否只有一个压缩点的出度为零*/                    {                        flag = true;                    }                    else                    {                        sum = 0;                        break;                    }                }            }        }        printf("%d\n",sum);    }    return 0;}

下面给一些数据,可以去测测自己的code

input3 31 22 33 13 31 22 12 35 41 42 43 45 45 51 22 33 11 44 55 61 22 33 11 44 55 32 21 22 13 21 22 16 61 22 33 11 44 55 35 61 22 33 11 44 55 45 74 11 22 33 11 44 55 45 61 22 33 11 44 55 17 91 22 33 14 55 66 44 77 11 76 61 22 33 14 55 66 44 41 22 33 11 44 41 22 33 14 15 61 22 33 15 15 43 47 91 22 33 15 15 43 44 77 66 4output31115200255401313



原创粉丝点击