Connected Components 连通分量及相关算法

Connected Components 连通分量及相关算法

引子

这是一篇久咕之作。

模板

todo

引导

首先,假设我们用的是前向星建图。

1
2
3
4
5
6
7
8
9
10
struct Edge {
int u, v, nx; // ,w
} e[MAXN << 1];

int head[MAXN], cntEd;

inline void addEdge(int u, int v) {
e[cntEd] = {u, v, head[u]};
head[u] = cntEd++;
}

然后应该写一个DFS。

1
2
3
4
5
6
7
8
9
void tarjan(int u) {
for (int i = head[u]; ~i; i = e[i].nx) {
int v = e[i].v;

if ( ) { }
}

if ( ) { }
}

下面想需要用到什么数组。

1
2
3
4
int low[MAXN];					//LOWLINK
int dfn[MAXN], idx; //NUMBER
int stk[MAXN], top; //STACK for cc
int scc[MAXN], sccnum; //SCC tags

然后想一下每个数组的意义,填进DFS。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

void tarjan(int u) {
dfn[u] = low[u] = ++idx;
stk[++top] = u;

for (int i = head[u]; ~i; i = e[i].nx) {
int v = e[i].v;

if (!dfn[v]) { //如果v结点未访问过
tarjan(v);
low[u] = min(low[u], low[v]);
} else if (!scc[v]) { //如果还在栈内
low[u] = min(low[u], dfn[v]);
}
}

if (low[u] == dfn[u]) { //后代不能找到更浅的点
sccnum++;
int x;
do {
x = stk[top--];
scc[x] = sccnum;
} while (x != u);
}
}

然后学会怎么用它。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

int main() {
memset(head, -1, sizeof head);
int n;

//input & build graph ...

for (int i = 1; i <= n; ++i) {
if (!dfn[i])
tarjan(i);
}

//scc[v] ...

return 0;
}

好了假装你会了。

当然要真的会了,可以试图去理解一下,DFS中的条件。

例题

SCC / Directed Roads

给一个n点n边有向无权图。问,有多少种反转边的方案,使图中无简单环。

思路也简单,每条边反转和不反转有$2^n$种方案。假如有一个$m$阶环,有两种方案是不行的——全反转和全不反转。所以对每个$m_i$阶环,其实方案有$2^{m_i}-2$种方案。

其他边都当$2$累乘即可。

我的代码:60847488

Tarjan 1972

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×