思路:
在有向无环图中,若任意点都能到达点A,那么有且仅有A点的出度为0,而题中可能包含环,通过缩环,构成新的有向无环图,若a欢迎b,则将a连向b,通过Taijan缩环模板处理,得到各点所在强连通分支,再通过出度判断,即可求解。
代码:
#include <iostream>
#include <string.h>
using namespace std;
const int MAX_N=10005;
struct edge
{
int to,next;
}e[5*MAX_N];
int p[MAX_N],eid;
void insert(int u,int v)
{
e[eid].to=v;
e[eid].next=p[u];
p[u]=eid++;
}
int dfn[MAX_N],low[MAX_N];
int idx=0;
int belong[MAX_N],scc=0;
int s[MAX_N],top=0;
bool instack[MAX_N];
int out[MAX_N];
void init()
{
eid=0;
memset(p,-1,sizeof(p));
memset(dfn,0,sizeof(dfn)); //一定要初始化为0,千万不能为-1......
memset(low,0,sizeof(low));
memset(instack,false,sizeof(instack));
memset(belong,0,sizeof(belong));
memset(out,0,sizeof(out));
}
void tarjan(int u)
{
dfn[u]=low[u]=++idx;
s[top++]=u;
instack[u]=true;
for(int i=p[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(instack[v])
{
low[u]=min(low[u],dfn[v]);
}
}
if(dfn[u]==low[u])
{
++scc;
do
{
belong[s[--top]]=scc;
instack[s[top]]=false;
}
while(s[top]!=u);
}
}
int main()
{
init();
int n,m;
cin>>n>>m;
for(int i=0;i<m;i++)
{
int a,b;
cin>>a>>b;
insert(a,b);
}
for(int i=1;i<=n;i++)
if(dfn[i]==0)
tarjan(i);
for(int i=1;i<=n;i++)
for(int k=p[i];k!=-1;k=e[k].next)
{
if(belong[i]!=belong[e[k].to]) //统计新图点的出度,a到b,若a,b不在同一个新点中,则a所在新点出度++
out[belong[i]]++;
}
int pos,tot=0;
for(int i=1;i<=scc;i++)
{
if(out[i]==0)
{
tot++;
pos=i;
}
}
for(int i=1;i<=n;i++) //若有不可达点,则一定不成立
if(!belong[i])
tot=0;
if(tot==1) //出度为0的点只能有一个,否则一定有人不欢迎另一人
{
int sum=0;
for(int i=1;i<=n;i++)
if(belong[i]==pos) //统计该新点中点的个数
sum++;
cout<<sum<<endl;
}
else
cout<<0<<endl;
return 0;
}