AcWing 1174. 受欢迎的牛 题解(tarjan dfs序时间戳+缩环成点)

11 篇文章 0 订阅
4 篇文章 0 订阅

AcWing 1174. 受欢迎的牛
求强连通分量的tarjan算法要记住

#include<bits/stdc++.h>

using namespace std;

const int N = 1e4 + 10, M = 5e4 + 10;

int h[N], e[M], ne[M], idx;
int n, m;
int stk[N], top;  //栈 
bool is_stk[N];  //标记这个点是否在栈内
int id[N];  //记录点在哪个连通分量内
int dfn[N];  //记录这个点自个儿的时间戳 
int low[N];  //记录这个点能到达的最小的时间戳
int timep;  //时间戳 
int scc_cnt;  //记录强连通分量的数量
int Size[N];  //记录连通分量内部点的数量
int dcout[N];  //记录连通分量的出度 
int ans;  //记录答案 
int ni; //记录符合条件的强连通分量的数量,如果大于1则题中所求量为0
 
void add(int a, int b){
	e[idx] = b;
	ne[idx] = h[a];
	h[a] = idx ++ ;
} 

void tarjan(int u){  //遍历u所在的连通分量 
	low[u] = dfn[u] = ++ timep;
	stk[ ++ top] = u;
	is_stk[u] = true;
	
	for(int i = h[u]; ~i; i = ne[i]){
		int j = e[i];
		if(!dfn[j]){  //如果这个点还没被搜索过 
			tarjan(j);
			low[u] = min(low[u], low[j]);
		}
		else if(is_stk[j]) low[u] = min(low[u], dfn[j]);
	}
	
	if(low[u] == dfn[u]){
		int y;
		++ scc_cnt; 
		do{
			y = stk[top -- ];
			is_stk[y] = false;
			id[y] = scc_cnt;
			Size[scc_cnt] ++ ;
		}while(y != u);
	}
}

int main()
{
	cin>>n>>m;
	memset(h, -1, sizeof h);
	for(int i = 0; i < m; i ++ ){
		int a, b;
		cin>>a>>b;
		add(a, b);
	}
	
	for(int i = 1; i <= n; i ++ ){
		if(!dfn[i]){  //如果这个点还没被tarjan过 
			tarjan(i);
		}
	}
	
	for(int i = 1; i <= n; i ++ ){
		for(int j = h[i]; ~j; j = ne[j]){
			int k = e[j];
			int a = id[i], b = id[k];  //i才是节点 
			if(a != b) dcout[a] ++ ; 
		}
	}
	
	for(int i = 1; i <= scc_cnt; i ++ ){  //遍历所有强连通分量 
		if(!dcout[i]){  //如果这个强连通分量的出度为0 
			ni ++ ;
			ans += Size[i];
			if(ni > 1){
				ans = 0;
				break;
			}
		}
	}
	
	cout<<ans<<endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值