【Luogu P2002&P2341】消息扩散/受欢迎的奶牛

Luogu P2002
Luogu P2341
使用强连通分量算法缩点
第一题统计入度为0的个数强连通分量数。
第二题的答案为当且仅当仅有一个强连通分量的出度为0时该强连通分量的节点数,原因如下:若一个强连通分量出度为0,则说明这个强连通分量的喜爱无法对外传递;若有多个强连通分量出度为0,则说明这几个强连通分量的喜爱无法对外传递,则不可能产生明星。
有关强连通分量的知识,可以看我的另一篇博客
【Luogu P3387】缩点模板(强连通分量Tarjan&拓扑排序)

AC代码

P2002:

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=1e5+10,maxm=5*1e5+10;
struct data
{
	int to,next;
}e[maxm];
int low[maxn],dfn[maxn],stk[maxn],head[maxn],tim,cnt,tot,in[maxn];
bool vis[maxn];
int val[maxn],scc[maxn],n,m,a,b;
void tarjan(int u)
{
	low[u]=dfn[u]=++tim;
	stk[++cnt]=u;
	vis[u]=true;
	for (int i=head[u];i;i=e[i].next)
	{
		int v=e[i].to;
		if (!dfn[v])
		{
			tarjan(v);
			low[u]=min(low[u],low[v]);
		}
		else 
		{
			if (vis[v]) low[u]=min(low[u],dfn[v]);
		}
	}
	if (low[u]==dfn[u])
	{
		tot++;
		while (true)
		{ 
			val[tot]++;
			scc[stk[cnt]]=tot;
			vis[stk[cnt]]=false;
			cnt--;
			if (stk[cnt+1]==u) break;
		}
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;i++)
	{
		scanf("%d%d",&a,&b);
		e[i].to=b;
		e[i].next=head[a];
		head[a]=i;
	}
	for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i);
	for (int i=1;i<=n;i++)
		for (int j=head[i];j;j=e[j].next)
		{
			int u=i,v=e[j].to;
			if (scc[u]!=scc[v])
				in[scc[v]]++;
		}
	int flag=0;
	for (int i=1;i<=tot;i++) if (!in[i]) flag++;
	printf("%d",flag);
	return 0;
}

P2341:

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=1e4+10,maxm=5*1e4+10;
struct data
{
	int to,next;
}e[maxm];
int low[maxn],dfn[maxn],stk[maxn],head[maxn],tim,cnt,tot,out[maxn];
bool vis[maxn];
int val[maxn],scc[maxn],n,m,a,b;
void tarjan(int u)
{
	low[u]=dfn[u]=++tim;
	stk[++cnt]=u;
	vis[u]=true;
	for (int i=head[u];i;i=e[i].next)
	{
		int v=e[i].to;
		if (!dfn[v])
		{
			tarjan(v);
			low[u]=min(low[u],low[v]);
		}
		else 
		{
			if (vis[v]) low[u]=min(low[u],dfn[v]);
		}
	}
	if (low[u]==dfn[u])
	{
		tot++;
		while (true)
		{ 
			val[tot]++;
			scc[stk[cnt]]=tot;
			vis[stk[cnt]]=false;
			cnt--;
			if (stk[cnt+1]==u) break;
		}
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;i++)
	{
		scanf("%d%d",&a,&b);
		e[i].to=b;
		e[i].next=head[a];
		head[a]=i;
	}
	for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i);
	for (int i=1;i<=n;i++)
		for (int j=head[i];j;j=e[j].next)
		{
			int u=i,v=e[j].to;
			if (scc[u]!=scc[v])
				out[scc[u]]++;
		}
	int flag=0;
	for (int i=1;i<=tot;i++) if (!out[i]) cnt=i,flag++;
	if (flag==1) printf("%d\n",val[cnt]);
	else printf("0");
	return 0;
}
posted @ 2019-11-08 22:21  Nanjo  阅读(124)  评论(0)    收藏  举报