poj2186 Popular Cows

博客详细介绍了如何解决POJ2186问题,该问题涉及到图论中的强连通分量。由于牛的仰慕关系具有传递性,博主解释了如何通过构建新图并寻找出度为0的强连通分量来确定受到所有牛仰慕的牛的数量。博主建议读者通过实践和画图来深入理解这个问题。
摘要由CSDN通过智能技术生成

Popular Cows
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 31782 Accepted: 12909

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

今天学习了强连通分量,应该说找强连通分量的函数要比找双联通分量函数的要简单一些的。


大意:给你n头牛,然后有m对关系,每对关系(a,b)说的是a牛仰慕b牛。

牛的仰慕具有传递性,也就是说如果a->b,b->c,那么有a->c。

然后问你这群牛中有多少头牛是受到所有牛仰慕的。


思路:

因为仰慕关系具有传递性,因此在一个强连通分量中的顶点:其中一头牛A如果仰慕一头牛B,那么A所在的强连通分量中的所有顶点都对牛B仰慕。

首先就是找出所有的双连通分量然后我们把所有的强连通分量缩成一个点,并构造新图。

(具体强连通的求解我是按照大白书上学习的)

最后做一次扫描,统计出度为0的强连通分量的个数。

如果个数为1,说明该强连通分量中的所有顶点都是符合条件的。否则是没有符合条件的牛的。



对于示例,缩点过程就像这样,最终可以得到3这个顶点是符合条条件的。

如果还是不怎么懂,读者可以自己画图理解一下,留言也可以。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <stack>
using namespace std;
const int MAXN=10000+10;
int n,m;
int dfn[MAXN],sccno[MAXN],dfs_clock,scc_cnt;
typedef vector<int>ve;
vector<ve>G(MAXN);
stack<int>S;
int dfs(int u)
{
    int lowu=dfn[u]=++dfs_clock;
    S.push(u);
    for(int i=0,l=G[u].size();i<l;++i)
    {
        int v=G[u][i];
        if(!dfn[v])
        {
            int lowv=dfs(v);
            lowu=min(lowu,lowv);
        }
        else if(!sccno[v])
        {
            lowu=min(lowu,dfn[v]);
        }
    }
    if(lowu==dfn[u])
    {
        scc_cnt++;
        while(1)
        {
            int x=S.top();
            S.pop();
            sccno[x]=scc_cnt;
            if(x==u)break;
        }
    }
    return lowu;
}

void find_scc()
{
    dfs_clock=scc_cnt=0;
    for(int i=0;i<n;++i)if(!dfn[i])dfs(i);
}

int out[MAXN];
int main()
{
    int i,j,l;
    scanf("%d%d",&n,&m);
    int u,v;
    while(m--)
    {
        scanf("%d%d",&u,&v);
        u--;
        v--;
        G[u].push_back(v);
    }
    find_scc();//搜索并找出强连通分量
    //缩点
    int pos,ans=0;
    for(i=0;i<n;++i)
        for(j=0,l=G[i].size();j<l;++j)
    {
        int v=G[i][j];
        if(sccno[i]!=sccno[v])
        {
            out[sccno[i]]++;
        }
    }
    //统计出度为0的“顶点
    for(i=1;i<=scc_cnt;++i)
    {
        if(!out[i])
        {
            pos=i;
            ans++;
        }
    }
    if(ans>1)puts("0");
    else
    {
        int sum=0;
        for(i=0;i<n;++i)
        {
            if(sccno[i]==pos)sum++;
        }
        printf("%d\n",sum);
    }
    return 0;
}









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值