2021-08-06

割点:

vector<long long>g[N];
int dfn[N], low[N], cut[N], deep, tag[N], sz[N];

//dfn记录深度,low记录最近的根节点的深度,cut保存割点,sz记录割点消失后其中一个子连通块的点数个数。

// v:当前点 r:本次搜索树的root
void tarjan(ll u, ll r) {  //u是遍历到的节点.
	
	dfn[u] = low[u] = ++deep;
	
	ll child = 0;
	
	for (unsigned i = 0; i < g[u].size(); i++) {
		
		ll v = g[u][i];
		
		if (!dfn[v]) {
			
			tarjan(v, r);

			sz[u] += sz[v];
			low[u] = min(low[u], low[v]);
			
			if (low[v] >= dfn[u] && u != r) {//不是根而且他的孩子无法跨越他回到祖先 
				cut[u] = 1;
				if (sz[v] % 2)tag[u] = 1;
			}
			
			if (r == u)child++; //如果是搜索树的根,统计孩子数目
		}
	
		else low[u] = min(low[u], dfn[v]);//已经搜索过了
	}
	if (child >= 2 && u == r)cut[r] = 1;
}

强连通分量:

#define MAX 10005
#define ll long long

vector<ll> g[MAX];
ll color[MAX], vis[MAX], stack[MAX], dfn[MAX], low[MAX], cnt[MAX];
//deep:节点编号 top:栈顶  sum:强连通分量数目
ll deep, top, sum, res = 0;

void tanjan(ll v) {
	dfn[v] = ++deep;
	low[v] = deep;   //(1)初始化dfn数组,同时将low设置为相同值
	vis[v] = 1;
	stack[++top] = v;//(2)入栈,作为栈顶元素,同时更新vis数组

	for (unsigned i = 0; i < g[v].size(); i++) {//(3)遍历所有可能到达的点
		ll id = g[v][i];
		if (!dfn[id]) {//如果这个点从没访问过,则先放问它,再用它更新low[v]的值
			tanjan(id);
			low[v] = min(low[v], low[id]); //他的儿子如果能连到更小的祖先节点,显然他也可以
		}
		else {
			if (vis[id]) {//不在栈中的点,要么没有访问,要么不能到达id,所以只需要判断栈中的
				low[v] = min(low[v], low[id]);
			}
		}
	}

	if (low[v] == dfn[v]) {//(4)自己和子节点形成了强连通分量,或者只有自己孤身一人
		color[v] = ++sum;
		vis[v] = 0;
		while (stack[top] != v) {//将从v开始所有的点取出
			color[stack[top]] = sum;//给予同一颜色
			vis[stack[top--]] = 0;//出栈要顺便修改vis
		}
		top--;
	}
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值