强连通分量

        连通:图中任意两个点可以相互抵达。

        强连通:有向图中任意两个点可以相互抵达。

        而一张图中的子图如果联通,我们称之为该图的强连通分量。

        

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

const int maxn=10005;
struct dot {
	int next[maxn],cd;
}a[maxn];
int n,m,sum,tim[maxn],low[maxn],t,tip[maxn];
//tim记录点的访问时间时间,low表示点通过图可以回溯到的点的访问时间中的最小值,tip标记元素是否在栈中,t表示时间
stack<int> k;

int minn(int p,int q) {
	if(p <= q) return p;
	else return q;
}

void dfs(int z) {
	t++;
	k.push(z);
	tip[z]=1;
	tim[z]=low[z]=t; //能参与深搜的点必然是还未被访问的节点
	if(a[z].cd != 0) {
		for(int i=1;i<=a[z].cd;i++) { //先遍历其所有分支
			if(tim[a[z].next[i]] == 0) {
				dfs(a[z].next[i]);
				low[z]=minn(low[z],low[a[z].next[i]]);
			}
			else if(tip[a[z].next[i]] == 1) {
                //如果其分支节点已经在栈中,说明这两个点必然在同一个强连通分量中
				low[z]=minn(low[z],low[a[z].next[i]]);
			}
		}
	}
	if(tim[z] == low[z]) { 
         //如果对z点的子树完成遍历后,low=tim,说明z点无法到达更早的节点,故z点为一个强连通分量的根节点
		while(k.top() != z) {
			tip[k.top()]=0;
			k.pop();
		}
		tip[z]=0;
		k.pop();
		sum++;
	}
}

int main() {
	cin>>n>>m;
	for(int i=1;i<=m;i++) {
		int x,y;
		cin>>x>>y;
		a[x].cd++;
		a[x].next[a[x].cd]=y;
	}
	for(int i=1;i<=n;i++) {
		if(tim[i] == 0) dfs(i);
	}
	cout<<sum;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值