基本方法和裸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;
}