TP

  • 强连通缩点模板
  • 双连通缩点模板
    • 边双连通
    • 点双连通

有向图

我们知道在一张 有向无环 图(也叫 DAG)中,肯定存在拓扑序。拓扑序的特殊顺序性质,能够允许我们在 O(n+m)O(n + m)O(n+m) 遍历这张图,还可以在图上用 dp 处理问题。

但大部分给的 有向图 都不是 DAG,用 Tarjan 算法,我们可以尝试转化,把环缩成点 —— 强连通分量。

在任意一个强连通分量中,内部的点两两之间都可以通过有向边到达

预处理缩点的时间是 O(n+m)O(n + m)O(n+m)

无向图

无向图本身两点之间就可以成环,所以没有环的说法。

分为两种:

  1. 边的双连通分量
  2. 点的双连通分量

在任意一个边双连通分量中,删去任意一条边不会使图不连通。

在任意一个点双连通分量中,删去任意一个点不会使图不连通;

双连通缩点后的图都长得像一棵树

强连通缩点模板

针对有向图

int h[N], rh[N], e[M], re[N], ne[M], idx;
void add(int h[], int a, int b) {e[idx] = b, re[idx] = a, ne[idx] = h[a], h[a] = idx++;
}
// Tarjan模板int dfn[N], low[N], tim;
int stk[N], top;
bool v[N];
int scc_cnt, id[N], siz[N];
//分量个数,属于哪个分量,分量大小void tarjan(int x) {dfn[x] = low[x] = ++tim;stk[++top] = x;v[x] = true;for (int i = h[x]; ~i; i = ne[i]) {int j = e[i];if (!dfn[j]) {tarjan(j);low[x] = min(low[x], low[j]);}else if (v[j])low[x] = min(low[x], dfn[j]);//也在栈中}if (dfn[x] == low[x]) {int y;scc_cnt++;do{y = stk[top--];v[y] = false;id[y] = scc_cnt;siz[scc_cnt]++;} while (y != x);}
}
 for (int i = 1; i <= n; i++)if (!dfn[i])tarjan(i);
 //缩点后重建图模板,去重unordered_map<ll, int> mp;for (int i = 0; i < idx; i++) {int b = e[i], a = re[i];//二维压成一维ll hash = a * N + b;if (id[b] != id[a] && !mp.count(hash)) {mp[hash] = 1;add(rh, a, b);}}
 //按拓扑序遍历图,直接反向遍历scc_cnt即可,无需记录入度for (int i = scc_cnt; i; i--) {//起点初始for (int g = rh[i]; ~g; g = ne[g]) {int j = e[g];//维护信息}}

双连通缩点模板

针对无向图

边双连通

int dfn[N], low[N], tim;
int stk[N], top;
bool is_bridge[M];
int dcc_cnt, id[N], siz[N];
//分量个数,属于哪个分量,分量大小void tarjan(int x, int from) {dfn[x] = low[x] = ++tim;stk[++top] = x;//双连通不需要维护 vfor (int i = h[x]; ~i; i = ne[i]) {int j = e[i];if (!dfn[j]) {tarjan(j, i);low[x] = min(low[x], low[j]);//记录桥if (dfn[x] < low[j])is_bridge[i] = is_bridge[i ^ 1] = true;}else if (i != (from ^ 1))low[x] = min(low[x], dfn[j]);//防止跟父节点更新就行}if (dfn[x] == low[x]) {int y;dcc_cnt++;do{y = stk[top--];id[y] = dcc_cnt;} while (y != x);}
}

点双连通

记录起来较为麻烦,需要特判根节点。

int dfn[N], low[N], tim;
int stk[N], top;
int dcc_cnt, root;
vector<int> dcc[N];//存储每个分量里有哪些点
bool cut[N];//记录割点void tarjan(int x) {dfn[x] = low[x] = ++tim;stk[++top] = x;if (x == root && h[x] == -1) { //如果只有单独一个点dcc_cnt++;//单独一个分量dcc[dcc_cnt].push_back(x);return;}int cnt = 0;//记录该点连接的割点个数for (int i = h[x]; ~i; i = ne[i]) {int j = e[i];if (!dfn[j]) {tarjan(j);low[x] = min(low[x], low[j]);if (dfn[x] <= low[j]) { cnt++;if (x != root || cnt > 1)cut[x] = true;//不是根节点时,因为肯定存在父节点,删去 x 分离了父节点与子节点//是根节点时,就要保证有两个子节点连到 x 上//这样才能说明 x 是割点dcc_cnt++;int y;do{y = stk[top--];dcc[dcc_cnt].push_back(y);} while (y != j);//到 j 就停止!dcc[dcc_cnt].push_back(x);//割点也放入//所以点双连通分量是有交集的}}else low[x] = min(low[x], dfn[j]);//点双连通可以随意取min}
}
 for (root = 1; root <= n; root++)if (!dfn[root])tarjan(root);

Tarjan算法 —— 强连通双连通缩点 模板相关推荐

  1. Tarjan算法学习1-双连通

    太久不做题,发现很多学过的算法又通通不记得了,或许因为当时既没有深刻理解,也没有及时总结.最近开始复习图论,说是复习,不如说重新学习更加恰当.算法是进入大学紧跟着c语言接触到的第二项"技术& ...

  2. POJ 3177 Redundant Paths (边双连通+缩点)

    <题目链接> <转载于 >>>  > 题目大意: 有n个牧场,Bessie 要从一个牧场到另一个牧场,要求至少要有2条独立的路可以走.现已有m条路,求至少要新 ...

  3. nyist120 校园网络 (Tarjan算法 / 强连通分量)

    校园网络(nyist 120) 解题思路请看代码块中的注释~ import java.util.Scanner; import java.util.Stack; import java.util.Ve ...

  4. Tarjan算法——边双和点双

    边双连通分量 边双连通图:如果一个无向连通图中,没有割边,那么这个无向连通图就是一个边双连通图. 一个无向图的极大边双连通子图就是它的其中一个边双连通分量. 我们要解释下这里"极大" ...

  5. 社群发现算法--强连通和连通在关联图谱中的应用

      本文介绍社群发现算法在关联图谱中的应用.社群发现算法是图算法中的一种,图算法是图分析的工具之一. 图算法提供了一种最有效的分析连接数据的方法,它们描述了如何处理图以发现一些定性或者定量的结论.图算 ...

  6. Codeforces 104C Cthulhu dfs暴力 || 点双连通缩点

    题目链接:点击打开链接 题意: 给定n个点m条边的无向图 问图中是否存在 有且仅有一个简单环和一些树,且这些树的root都在这个简单环上. 瞎写了个点双..== #include <stdio. ...

  7. `Computer-Algorithm` Tarjan算法,强连通分量SCC,PBCC割点,EBCC割边/桥

    Contents EBCC 例题 PBCC 涉及割点/PBCC时的解决思路 例题 SCC 过去分析 例题 EBCC Some properties of the algorithm: + for a ...

  8. 双连通图强连通图概念解释以及tarjan算法求解该类问题总结

    最近看了看类的相关题,感觉简单的题过于模板,但是对于难题的转化,如果对与这方面的概念不清楚,很难写,故总结一下. PS:博客里部分内容会和离散数学中的图论知识有联系,如果没有了解过相关知识可能比较难理 ...

  9. 海亮DAY8 关于Tarjan算法用于割点割边相关感受

    Tarjan 简介 Tarjan算法在求割点,割边,连通分量方面及其高效,在军事,交通,设计等方面有重要作用. 由于Tarjan算法思想并不难懂,在此不放上Tarjan算法的具体介绍. [Usaco2 ...

最新文章

  1. 文档自动摘要及案例实现
  2. Linux运行cat进程,linux下如何使用某个用户启动某个进程?
  3. WindowsPowerShell常用命令
  4. Redis命令参考简体中文版
  5. Override and Overload (重写和重载)
  6. java nio doug_深入的聊聊 Java NIO
  7. 杭电acm 1846 Brave Game(巴什博弈)
  8. NOX的使用之学习篇【三】
  9. 最近在修改statusBar,添加几张图片.编译源码包时,一直提示无法找到R.drawable.xxxx必须手动编译下指定的图片文件生成R.
  10. AS3 XML全部用法
  11. bat代码如何处理中文目录
  12. 简单记录 03.21
  13. bind服务器响应,DNS和Bind服务器
  14. cattee翻译_0302 echo、重定向、管道、cat、tee
  15. 浙大吴飞与贾扬清经典十问!
  16. 高效沟通的方法与技巧(转自飞马网)
  17. Verilog 实现千兆网UDP协议 基于88E1111--板级验证--增加ARP
  18. 教老妈学认字的战斗史
  19. 抖音如何推动音乐的流行?看完这篇文章你就明白了
  20. 忍者必须死显示无法连接服务器,忍者必须死为什么不能登录

热门文章

  1. 直播预告 | NeurIPS 专场八
  2. python学习第八天
  3. PHP你所不知道的事--empty
  4. 聆听朱清时教授讲创新
  5. 问卷调查样本量的确定方法
  6. shell 脚本返回上级目录_Linux命令:使用cd和alias命令快速返回上级目录
  7. linux下怎么退出vi编辑器,按esc没有用;vim recording
  8. 【C语言】之实现闰年判断
  9. 18岁误入网站_是市场驱动的技术领先现代医学误入歧途
  10. 基于FDC2214传感器的手势识别装置(MSP430)