定义:一个有向图中,一个图可以分成几个分支,每个分支的任意两个结点如果都有路径使得互相可达,那么称这个分支为强连通分支
现在要给一个有向图,求出强连通分支,可以利用Tarjan发明的算法
求出强连通分支之后,可以根据题目,把每个强连通分支进行缩点,缩点之后的图会变成一个有向无环图(DAG),就可以进行一些算法(如DP, 最短路,最小生成树之类的)
模板:
const int N = 505; int n; vector<Edge> g[N]; int pre[N], dfn[N], dfs_clock, sccn, sccno[N]; stack<int> S; void dfs_scc(int u) { pre[u] = dfn[u] = ++dfs_clock; S.push(u); for (int i = 0; i < g[u].size(); i++) { int v = g[u][i].v; if (!pre[v]) { dfs_scc(v); dfn[u] = min(dfn[u], dfn[v]); } else if (!sccno[v]) dfn[u] = min(dfn[u], pre[v]); } if (pre[u] == dfn[u]) { sccn++; while (1) { int x = S.top(); S.pop(); sccno[x] = sccn; if (x == u) break; } } } void find_scc() { dfs_clock = sccn = 0; memset(sccno, 0, sizeof(sccno)); memset(pre, 0, sizeof(pre)); for (int i = 1; i <= n; i++) if (!pre[i]) dfs_scc(i); }
1、判断是否是一个强连通图
裸题直接判断,还要注意是否都在一个连通块内,这个看找出来的强连通分支个数是不是1即可
2、强连通缩点后,保留点权(可以是分支点权总和,个数等等)
就在缩点的时候,不断出栈的一步进行小修改即可
HDU 1269 迷宫城堡 此题可用来验证模板 1类
POJ 3180 The Cow Prom 找强连通分量中元素个数大于1的个数 2类
1、加几条边使得图强连通:
先缩点,然后计算缩完的图入度为0和出度为0的点的个数,较大的那个必然是答案
要注意就是如果一开始就强连通,是要输出0的
2、从哪些点出发(或者说要放几个点),使得所有点都能走到
缩点后所有入度为0的点就是要放的位置
HDU 2767 Proving Equivalences 1类
HDU 3836 Equivalent Sets 1类
HDU 1827 Summer Holiday 2类
POJ 1236Network of Schools 1 + 2 类
POJ 2553 The Bottom of a Graph 这题是找出度为0的强连通分支
POJ 2186 Popular Cows 这题找有几个点是别的点都能到达的,注意判断出度为0的点大于1的时候,答案应该是0
POJ 2375Cow Ski Area 根据题意建模之后就是1类问题
一般一些问题,如果是一个有向无环图可以解决的情况下,如果图变成可能有环的时候,就要考虑缩点,而缩点之后的点权根据题目而定,然后剩下就是在缩点之后的图上,去解决另外一个问题了
HDU 3072 Intelligence System 缩点之后跑最小树形图
HDU 3861 The King’s Problem 缩点之后跑二分图匹配最小路径覆盖
HDU 3639 Hawk-and-Chicken 缩点之后DP
POJ 2762 Going from u to v or from v to u? 缩点之后拓扑排序,判断图中不会出现分支
POJ 3160 Father Christmas flymouse 缩点之后DP(dag上的最长路)
POJ 3114Countries in War 缩点之后跑最短路
POJ 3592 Instantaneous Transference 根据题意建模,然后缩点之后DP
有向仙人掌图判定:
HDU 3594 Cactus
就只要在找强连通分支过程中,如果出现了环,就把路径上的点值都+1,如果有一个时刻出现某一点值为2,那么肯定就不满足了,然后在判断一下是否在一个连通块内即可
POJ 1904 King's Quest
结合了二分图匹配的知识,把问题转化为强连通去解决