题解 P2341 【[HAOI2006]受欢迎的牛】
NephrenRuq · · 题解
这题的思路是tarjan求强联通分量
题意为对于一张有向图,找出一些点,使得所有点均能到达该点,求出这些点的数量
首先我们求出所有强联通分量
显然,若1能到达2,(2,3,4)是一个强联通分量,
那么1肯定能到达2,3,4所有点。
于是我们可以将此题简化成:
找出一个强联通分量,使得所有强联通分量均能到达强联通分量,求出此强联通分量的元素个数
易证明只有一个强联通分量满足要求
那么满足条件的分量是哪个呢?其实这不需要用搜索
只要满足入度为0的强联通分量不超过1,那么tarjan求得最远的强联通分量就是所求解
以下是代码:
#include<iostream>
#include<cstdio>
using namespace std;
int i,j,k,m,n;
int top=0,cnt=0,num=0;
int First[100001],Next[100001],Last[100001],a[100001],pe[100001],pupuvovovovo[100001];
bool b[100001],b2[100001];
int q[100001],dfn[100001],low[100001],fa[100001];
void add(int x,int y)
{
k++;a[k]=y;
if(First[x]==0)First[x]=k;
else Next[Last[x]]=k;
Last[x]=k;
}
void tarjan(int x)
{
top++;cnt++;
dfn[x]=low[x]=cnt;
q[top]=x;
b[x]=true;
int t=First[x];
while(t!=0)
{
int v=a[t];
if(dfn[v]==0)
{
tarjan(v);
if(low[v]<low[x])
low[x]=low[v];
}
else if(b[v]&&dfn[v]<low[x])
low[x]=dfn[v];
t=Next[t];
}
if(dfn[x]==low[x])
{
n++;
while(q[top+1]!=x)
{
pe[n]++;
fa[q[top]]=n;
b[q[top]]=false;
top--;
}
}
}
int main()
{
scanf("%d%d",&n,&m);
int x,y;
k=0;
for(i=1;i<=m;i++)
{
scanf("%d %d",&x,&y);
add(x,y);
}
int m=n+1;
for(i=1;i<=m-1;i++)
{
if(dfn[i]==0)
tarjan(i);
}
for(i=1;i<=m-1;i++)
{
for(int o=First[i];o;o=Next[o])
if(fa[i]!=fa[a[o]])
pupuvovovovo[fa[i]]++;
}
int pp=0;
for(i=m;i<=n;i++)
if(pupuvovovovo[i]==0)pp++;
if(pp==1)
cout<<pe[m];
else cout<<0;
}