POJ 2186 Popular Cows tarjan缩点算法

Posted icode-xiaohu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ 2186 Popular Cows tarjan缩点算法相关的知识,希望对你有一定的参考价值。

  题意:给出一个有向图代表牛和牛喜欢的关系,且喜欢关系具有传递性,求出能被所有牛喜欢的牛的总数(除了它自己以外的牛,或者它很自恋)。

  思路:这个的难处在于这是一个有环的图,对此我们可以使用tarjan算法求出强连通分量,把强连通分量压缩成一个点,构成一个新的图,这个图一定是没有环的,如果有环就跟强连通分量的矛盾了。压缩成无环图以后这个图里面的点是不具有方向的,我们通过遍历每个节点所能连到的点,如果两点的id值即所在的强连通分量区域不同时,我们就把这个节点的出度加1。最后去找那些出度等于0的点,如果没有或者超过1,那这图的答案是0,因为如果有两个点他们的出度都是0,那么意味着这两个点之间没有关系,所以地图中不可能出现一头牛被所有的牛喜欢。

  需要注意的地方,在一开始我的连通分量的id记录出错了,原因是我的第一个点在主函数里入栈,导致有些点没有被记录。后来受无向图的惯性思维的影响,又把判断pa != v的条件加上了,这个是有向图,是绝对不可以加这个判定的!具体代码如下:

#include<cstdio>
#include<stack>
#include<cstring>
#include<iostream>
using namespace std;
#define maxn 10010
struct EDGE
{
    int to,nxt;
} edge[maxn*5];
int head[maxn],id[maxn],dfn[maxn],low[maxn],tot,sum;
stack<int> s;
int all[maxn];
void tarjan(int u,int fa)
{
    s.push(u);
    dfn[u] = low[u] = ++tot;
    for(int i = head[u]; i != -1; i = edge[i].nxt)
    {
        int v = edge[i].to;
        if(!dfn[v])
        {
            tarjan(v,u);
            low[u] = min(low[v],low[u]);
        }
        else /*if(v != fa)*/ low[u] = min(low[u],dfn[v]);
    }
    if(low[u] == dfn[u])
    {
        sum++;
        while(!s.empty())
        {
            int num = s.top();
            s.pop();
            id[num] = sum;
            all[sum]++;
            if(u == num) break;
        }
    }
    return ;
}
int main()
{
    int n,m,x,y;
    while(~scanf("%d%d",&n,&m))
    {
        memset(head,-1,sizeof(head));
        for(int i = 0; i < m; i++)
        {
            scanf("%d%d",&x,&y);
            edge[i].to = y;
            edge[i].nxt = head[x];
            head[x] = i;
        }
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(id,0,sizeof(id));
        tot = 0,sum = 0;
        while(!s.empty()) s.pop();
        memset(all,0,sizeof(all));
        for(int i = 1; i <= n; i++)
        {
            if(!dfn[i])
            {
                tarjan(i,-1);
            }
        }
        //cout<<"sum = "<<sum<<endl;
        int vis[maxn];
        memset(vis,0,sizeof(vis));
        int du[maxn];
        memset(du,0,sizeof(du));
        /*for(int i = 1;i <= sum;i++)
        {
            cout<<"all = "<<all[i]<<endl;
        }*/
        for(int u = 1; u <= n; u++)
        {
            for(int j = head[u]; j != -1; j = edge[j].nxt)
            {
                int v = edge[j].to;
                if(id[u] != id[v])
                {
                    du[id[u]]++;
                }
            }
        }
        int sub = 0,last = 0;
        for(int i = 1; i <= sum; i++)
        {
            if(du[i] == 0)
            {
                sub++;
                last = i;
            }
        }
        if(sub != 1) puts("0");
        else printf("%d\n",all[last]);
    }
    return 0;
}

 

以上是关于POJ 2186 Popular Cows tarjan缩点算法的主要内容,如果未能解决你的问题,请参考以下文章

Popular Cows(POJ 2186)

Poj2186Popular Cows

POJ 2186 Popular Cows

Popular Cows POJ - 2186(强连通分量)

POJ 2186 Popular Cows(Targin缩点)

POJ2186 Popular Cows [tarjan 缩点]