强连通分量Tarjan算法

前言:这个taryan算法其实本质上就是一个dfs,我们会先处理晚访问的节点(这个不去模拟一遍是很难理解的)


在这里插入图片描述

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;

int n,m;
const int N = (int)5e4+5;
int e[N],ne[N],h[N],idx = 0;

int dfn[N],low[N],tot = 0;  // 一个是时间戳一个是追溯值
int stk[N],instk[N],top = 0; // 模拟栈
int scc[N],siz[N],cnt = 0; // 记录答案

void add(int a,int b){
	e[++idx] = b , ne[idx] = h[a] , h[a] = idx;
}

void taryan(int x){
	// 先入栈以及编号
	dfn[x] = ++tot, low[x] = tot;
	stk[++top] = x, instk[x] = 1;
	
	for(int i=h[x];i;i=ne[i]){
		int to = e[i];
		if(!dfn[to]){
			// 没被访问
			taryan(to);
			low[x] = min(low[x],low[to]);   // 返回的时候同时更新
		}else if(instk[to]){
			low[x] = min(low[x],dfn[to]); 
			 // 这一点值得注意,一定要是在
            // 栈中的 
            // 这个说明 y 是 x 的祖先节点或者左边节点
            // 为什么这个是 dfn 而不是 low 其实这两个是等价的 
		}
	} 
	// 离开x,记录以 x 为根的强联通分量
	if(low[x]==dfn[x]){
		int y;++cnt;
		do{
			y = stk[top--] , instk[y] = 0;
			scc[y] = cnt, siz[cnt]++; // 更新强联通分量的编号以及大小 
		}while(x!=y);
	}
}

int main(){
	cin >> n >> m;
	for(int i=1;i<=m;i++){
		int u,v; cin >> u >> v;
		add(u,v);
	}
	for(int i=1;i<=n;i++){
		if(scc[i]==0){
			taryan(i);
		}
	}int ans = 0;
	for(int i=1;i<=cnt;i++){
		if(siz[i]>1) ans++;
	}
	cout << ans;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wniuniu_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值