这是我做的第一道强连通分量,当然是找模板题来做。。。
此题大致意思就是:
现在告诉你一些关系,这些关系的形式是A B,表示A牛认为B牛受欢迎,如果A牛认为B牛受欢迎,B牛认为C牛受欢迎,那么A牛也会认为C牛受欢迎,现在问你有多少牛是其他所有牛都认为受欢迎的。
解题思路:
强连通分量的模板题。。。
1.首先用强连通分量缩点
2.如果缩点之后,只有一个点出度为0,那么这个点中的所有点都是,统计一下答案就行了。每一个强连通分量中的点是可以互相到达的,意思就是说一个强连通分量中的牛互相认为都是受欢迎的,那么如果有一只牛A认为另一头其他强连通分量中的牛B受欢迎,那么根据上面的题意就知道,牛A所在的强连通分量中的所有牛,会认为牛B所在的强连通分量中的所有牛,都是受欢迎的。(自己理解一下应该不难)所以要所有牛都认为你受欢迎,其他所有强连通分量就都会有出边连向其他强连通分量,最后只剩下一个强连通分量是出度为0的,也就是所有牛都认为其都受欢迎。
3.如果有几个点的出度为0,那么输出0,因为所有牛都还没有关系联系起来,那更别说有所有牛都认为受欢迎的牛。
代码(tarjan算法):
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
using namespace std;
int du[10010],dfn[10010],low[10010],head[10010];
int blong[10010],vis[10010];
int sum=0,cnt=0,tot=0,n,m,ti;
int stack[10010];
struct edgee
{
int next,to;
}edge[100050];
void addedge(int u,int v)
{
edge[tot].next=head[u];
edge[tot].to=v;
head[u]=tot++;
}
void dfs(int a)
{
dfn[a]=low[a]=++ti;
stack[++sum]=a;
vis[a]=1;
for(int i=head[a];i!=-1;i=edge[i].next)
{
int b=edge[i].to;
if(!vis[b])
{
dfs(b);
low[a]=min(low[a],low[b]);
}
else
if(vis[b])
low[a]=min(low[a],dfn[b]);
}
if(dfn[a]==low[a])
{
cnt++;
int v;
do
{
v=stack[sum];
du[v]=cnt;
vis[v]=2;
--sum;
}
while(v!=a&&sum>0);
}
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
int x,y;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
addedge(x,y);
}
for(int i=1;i<=n;i++)
{
if(!vis[i])
dfs(i);
}
for(int i=1;i<=n;i++)
{
for(int j=head[i];j!=-1;j=edge[j].next)
if(du[i]!=du[edge[j].to])
blong[du[i]]++;
}
int ans,pbs=0;
for(int i=1;i<=cnt;i++)
if(!blong[i])
{
pbs++;
ans=i;
}
if(pbs==1)
{
int Yif=0;
for(int i=1;i<=n;i++)
if(du[i]==ans)
Yif++;
printf("%d",Yif);
}
else
printf("0");
return 0;
}
如果有什么问题,欢迎评论。
如果强连通分量不懂,这里有链接(tarjan算法)——https://www.byvoid.com/blog/scc-tarjan/