首页 > 其他分享 >强连通分量、缩点

强连通分量、缩点

时间:2024-04-16 17:35:27浏览次数:10  
标签:缩点 连通 int dfn MAXN low 分量

强连通分量

定义:强连通分量是指一个任意两点都可互相到达的极大子图。

求解思路和桥、割点和边双连通分量很类似。

首先跑出一颗dfs树,令 \(dfn_u\) 表示 \(u\) 的时间戳,\(low_u\) 表示 \(u\) 的子树中仅通过非树边能到达的 \(\min \{dfn_v\}\)。

比如下图:

在这张图中,黑色边为树边,红色边为非树边,黑色数字表示编号,红色表示 \(dfn\),蓝色数字表示 \(low\)。

这些点是强连通分量:

可以发现,所有强连通分量中 \(dfn\) 最小的结点一定 \(dfn_u=low_u\),实际上这也很容易理解,如果自己子树中没有通向自己祖先的边,则代表这一部分是独立的。

所以我们可以开一个栈,栈中按dfs序记录结点。如果发现了一个结点的 \(dfn_u=low_u\),则不断弹出栈顶直到弹出 \(u\),弹出的结点就是一个强连通分量。

可是该怎么求解 \(low_u\) 呢?

根据定义,我们可以这样求:

设树上有一对条边 \(u\rightarrow v\),

  • 若 \(u\rightarrow v\) 的边是树边,则更新 \(low_u \leftarrow \min (low_u,low_v)\)。
  • 若 \(u\rightarrow v\) 的边不是树边且 \(v\) 不在另一个强连通分量,则更新 \(low_u\leftarrow\min(low_u,dfn_v)\)。
  • 否则,什么也不做。

代码

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

const int MAXN = 500001, MAXM = 2000001;

int n, m, dfn[MAXN], low[MAXN], tot, stk[MAXN], top, color, col[MAXN];
vector<int> e[MAXN];

void dfs(int u, int fa) {
  dfn[u] = low[u] = ++tot, stk[++top] = u;
  for(int v : e[u]) {
    if(!dfn[v]) {
      dfs(v, u);
      low[u] = min(low[u], low[v]);
    }else if(!col[v]) {
      low[u] = min(low[u], dfn[v]);
    }
  }
  if(low[u] == dfn[u]) {
    color++;
    for(; dfn[stk[top]] >= dfn[u]; col[stk[top--]] = color) {
    }
  }
}

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  cin >> n >> m;
  for(int i = 1, u, v; i <= m; ++i) {
    cin >> u >> v;
    e[u].push_back(v);
  }
  for(int i = 1; i <= n; ++i) {
    if(!dfn[i]) {
      dfs(i, 0);
    }
  }
  cout << color << "\n";
  for(int i = 1; i <= n; ++i) {
    cout << col[i] << " ";
  }
  return 0;
}

标签:缩点,连通,int,dfn,MAXN,low,分量
From: https://www.cnblogs.com/yaosicheng124/p/18138760

相关文章

  • Tarjan 求双连通分量(点双连通分量、边双连通分量)
    注意:本文只针对无向图。对于无向图,显然不能只考虑简单的连通关系,应该研究一些更强的连通关系:双连通。前置芝士点双连通分量:若一个连通分量任意两点间都存在至少两条不经过(除起点和终点外)相同点的路径,我们就称这个连通分量为点双连通分量。边双连通分量:同理,若一个连通分量......
  • 连通性+ 1
    早在普及组的时候,我们就学会了:DFS(BFS)搜连通块并查集在加边的情况下动态维护连通块(支持离线处理删边)现在,我问你:我删去一个点/边,判断剩下的图存在原本某两个连通的点现在不连通?我随机删去一条边,判断剩下的图中某两个点是否一定连通?我随机给你一些点,判断其中两两是......
  • 边双连通分量
    边双连通分量我们令双连通表示两个节点之间段开一条边还是连通的。边双连通分量表示求出几个最大的点集,使得任意一个点集中点两两双连通。例题luoguP8436方法1我们发现,如果两个节点原先连通但不是双连通,肯定他们之间的路径是经过某一座桥,所以可以求出来桥,把桥拆......
  • 聚水潭与金蝶云星空对接集成退货退款查询连通[聚水潭][销售退货单标准新增]-v1(聚水潭
    聚水潭与金蝶云星空对接集成退货退款查询连通[聚水潭][销售退货单标准新增]-v1(聚水潭--销售退货对接-P-12495392-这个店铺的数据)接入系统:聚水潭聚水潭是SaaS协同平台、电商ERP软件。聚水潭成立于2014年,创始人兼CEO骆海东拥有近三十年传统及电商ERP的研发和实施部署经验。......
  • [转]Docker 两个不同网络间实现连通
    原文地址:Docker两个不同网络间实现连通-西瓜君~-博客园一、启动不同网络的容器1、启动两个bridge(自带默认)桥接的容器[root@yang~]#dockerrun-it--nametomcat1tomcat[root@yang~]#dockerrun-it--nametomcat2tomcat#查看容器[root@yang~]#dockerps......
  • Python环境下一种改进小波分解方法-用于多分量信号的分解
    小波通俗的讲就是一种振幅表现为在正负之间震荡的波形。小波变换在基于短时傅立叶变换的前提下,又加入了其所没有的可随频率变化的“时间-频率”窗口,其能对时间、频率进行局部化分析,并且对待处理信号通过多尺度处理使其表现为时-频细分的特点,是一种能突出信号时频特点以及细节的......
  • 强连通分量随记随忘
    vis用于判断某个点是否在栈中tot表示强连通分量的数量belong[x]表示点x所属的强连通分量all[]与tot变量相关,表示此强连通分量的点的数量outd[]与tot变量相关,表示此强连通分量的出度模板代码如下:#include<bits/stdc++.h>usingnamespacestd;constintN=1e4+5;intn,m,......
  • 太阳之华 连通块计数
    C-太阳之华_牛客小白月赛89(nowcoder.com)思路:可以发现,最多经过一次操作就能知道结果:全是蓝色:蓝方胜全是红色:红方胜红方经过一次操作:存在一个连通块扩散等于蓝色个数:红方胜否则,红蓝一直重复进行,平局因此,对棋盘进行一次遍历,将所有红色连通块全部找出来并记上标记(类......
  • DFS求解连通块问题
    DFS求解连通块问题#include<bits/stdc++.h>usingnamespacestd;charg[35][65];intvis[35][65],num,res;intdx[]={0,1,0,-1},dy[]={1,0,-1,0};voiddfs(intx,inty){if(x<1||x>30||y<1||y>60||g[x][y]=='0'||vis[x][y])return;vis[x][......
  • 7-5 列出连通集
    给定一个有N个顶点和E条边的无向图,请用DFS和BFS分别列出其所有的连通集。假设顶点从0到N−1编号。进行搜索时,假设我们总是从编号最小的顶点出发,按编号递增的顺序访问邻接点。输入格式:输入第1行给出2个整数N(0<N≤10)和E,分别是图的顶点数和边数。随后E行,每行给出一条边的两个......