[洛谷P2002]消息扩散

本文介绍了一种解决有向图信息传播问题的算法。通过使用Tarjan算法进行强连通分量缩点,找到入度为0的点,确定信息传播的起点,从而计算最少需要将信息传递给多少个节点,使所有节点都能接收到信息。

题目大意:给你一张有向图,在一个点上的信息能沿着有向边扩散到另一个点,然后可以继续扩散。问至少把信息给多少个点,才能使所有点都收到信息。

解题思路:首先求强连通分量缩点,一个强连通分量里的一定能从任意一个点传播到另一个点。

用Tarjan缩点即可。

然后只要找新图拓扑序中入度为0的点即可,因为入度不为0的点一定能从另一个点得到信息,而入度为0的点无法从别的点上得到信息。

由于我们只需要找入度为0的点,而不关心每个点的入度实际是多少,所以只需要用原图的边即可,只要连接的两个点属于不同的强连通分量,就给终点所属的强连通分量入度+1。最后统计答案即可。

C++ Code:

#include<cstdio>
#include<cctype>
#include<cstring>
#define N 100005
int n,m,head[N],dfn[N],low[N],sta[N],stk,idx,ltfl,ys[N],deg[N];
bool vis[N];
struct edge{
	int from,to,nxt;
}e[1000005];
inline int readint(){
	char c=getchar();
	for(;!isdigit(c);c=getchar());
	int d=0;
	for(;isdigit(c);c=getchar())
	d=(d<<3)+(d<<1)+(c^'0');
	return d;
}
void tarjan(int now){
	vis[sta[++stk]=now]=true;
	dfn[now]=low[now]=++idx;
	for(int i=head[now];i;i=e[i].nxt)
	if(!dfn[e[i].to]){
		tarjan(e[i].to);
		if(low[now]>low[e[i].to])low[now]=low[e[i].to];
	}else
	if(vis[e[i].to]&&low[now]>dfn[e[i].to])
	low[now]=dfn[e[i].to];
	if(low[now]==dfn[now]){
		++ltfl;
		int k;
		do{
			k=sta[stk--];
			vis[k]=false;
			ys[k]=ltfl;
		}while(k!=now);
	}
}
int main(){
	stk=ltfl=0;
	n=readint(),m=readint();
	for(int i=1;i<=m;++i){
		int u=readint(),v=readint();
		e[i]=(edge){u,v,head[u]};
		head[u]=i;
	}
	memset(dfn,0,sizeof dfn);
	memset(low,0,sizeof low);
	for(int i=1;i<=n;++i)
	if(!dfn[i]){
		memset(vis,0,sizeof vis);
		idx=0;
		tarjan(i);
	}
	memset(deg,0,sizeof deg);
	for(int i=1;i<=m;++i)
	if(ys[e[i].from]!=ys[e[i].to])
	++deg[ys[e[i].to]];
	int ans=0;
	for(int i=1;i<=ltfl;++i)
	if(!deg[i])++ans;
	printf("%d\n",ans);
	return 0;
}

 

转载于:https://www.cnblogs.com/Mrsrz/p/7763264.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值