tarjan缩点

基本方法和裸tarjan差不多

在弹出的时候记录节点祖先

在处理完后搜索每个节点及其相连的节点,若两点的祖先不同,则入度++

poj2186 popular cow

入度为1的分量连边:n+1/2;

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
int dfn[10001],low[10001],a,b,c,top,tot,cnt,r[10001],head[50001],vis[10001],zh[10010],siz[10001],bel[10010],gg;
struct node
{
    int to,next;
}edge[100001];
int add(int s,int t)
{
    edge[++cnt].to=t;
    edge[cnt].next=head[s];
    head[s]=cnt;
}
int tarjan(int f)
{
    tot++;top++;
    dfn[f]=low[f]=tot;
    vis[f]=1;zh[top]=f;
    for(int i=head[f];i!=0;i=edge[i].next)
    {
        int v=edge[i].to;
        if(!dfn[v])
        {
            tarjan(v);low[f]=min(low[f],low[v]);
        }
        else if(vis[v]) low[f]=min(low[f],low[v]);
    }
    if(dfn[f]==low[f])
    {
        gg++;
        while(zh[top]!=f)
        {
            bel[zh[top]]=gg;
            siz[gg]++;          
            vis[zh[top]]=0;
            top--;
        }
        top--;vis[f]=0;
        bel[f]=gg;siz[gg]++;
    }
}
int main()
{
    cin>>a>>b;
    gg=0;
    cnt=top=tot=0;
    memset(vis,0,sizeof(vis));
    memset(r,0,sizeof(r));
    memset(siz,0,sizeof(siz));
    for(int i=1;i<=b;i++)
    {
        int x,y;cin>>x>>y;add(x,y);
    }
    for(int i=1;i<=a;i++)
    {
        if(!dfn[i]) tarjan(i);
    }
    for(int i=1;i<=a;i++)
    {
        for(int j=head[i];j!=0;j=edge[j].next)
        {
            int ne=edge[j].to;
            if(bel[i]!=bel[ne]) r[bel[i]]++;
        }
    }
    int ans=0;int q=0;
    for(int i=1;i<=gg;i++)
    {
        if(r[i]==0)
        {
            ans=i;q++;
        } 
    }
    if(q!=1) cout<<"0"<<endl;
   else 
   {
        cout<<siz[ans]<<endl;
   }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值