POJ 2186 Popular Cows

本文介绍了一种利用邻接表构建图的方法,并通过强连通分量缩点将其转化为有向无环图(DAG)。通过判断DAG中出度为0的节点数量来确定解的存在性及具体数值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

邻接表建图,强连通分量缩为有向无环图(DAG)中的一点,若DAG中出度为0的个数有1个以上,则解不存在,若出度为0的点有1个,则解为该点强连通分量中包含的点的个数

#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<vector>
#include<queue>
#include<map>
#include<stack>

using namespace std;

const int maxm=100010;
const int maxn=10010;

int ind,cnt,st[maxn],dfn[maxn],low[maxn],size,n,outdegree[maxn],time[maxn],v[maxm],first[maxn],next[maxm],num[maxn];
bool instack[maxn];

int solve(){
    memset(outdegree,0,sizeof(outdegree));
    for(int i=1;i<=n;i++)
        for(int j=first[i];j!=-1;j=next[j])
            if(time[v[j]]!=time[i])
                outdegree[time[i]]++;
    int out=0,ans;
    for(int i=1;i<=cnt;i++)
        if(!outdegree[i]) { out++; ans=num[i]; }
    if(out!=1) return 0;
    return ans;
}

void tarjan(int x){
    dfn[x]=low[x]=++ind;
    st[++size]=x;
    instack[x]=true;
    for(int i=first[x];i!=-1;i=next[i])
        if(!dfn[v[i]]){
            tarjan(v[i]);
            if(low[x]>low[v[i]]) low[x]=low[v[i]];
        }
        else if(instack[v[i]]&&dfn[v[i]]<low[x]) low[x]=dfn[v[i]];
    if(low[x]==dfn[x]){
        cnt++;
        for(int i=st[size--];i!=x;i=st[size--]){ time[i]=cnt; num[cnt]++; instack[i]=false; }
        time[x]=cnt;instack[x]=false;num[cnt]++;
    }
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("a.in", "r", stdin);
#endif
    int m;
    while(cin>>n>>m){
        memset(first,-1,sizeof(first));
        int u;
        for(int i=0;i<m;i++){
            cin>>u>>v[i];
            next[i]=first[u];
            first[u]=i;
        }
        memset(instack,false,sizeof(instack));
        memset(dfn,0,sizeof(dfn));
        ind=size=cnt=0;
        for(int i=1;i<=n;i++)
            if(!dfn[i])
                tarjan(i);
        cout<<solve()<<endl;
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值