[强连通分量]poj2186_Popular Cows

                                                   这是我做的第一道强连通分量,当然是找模板题来做。。。

此题大致意思就是:

      现在告诉你一些关系,这些关系的形式是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/


  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值