求强连通分量Tarjan算法
int dfn[16]; // 时间戳 int dfn_num = 0; // 时间 int low[16]; // 节点u所能访问到的最小时间戳 int inSt[16]; // 节点u是否在栈中. int st[16]; int top = 0; // 我们维护的信息. int col[16]; // 给节点染色, 同一个连通块的节点应该是同一个颜色的. int col_num = 0; // 颜色值. int size[16]; // 每个颜色值所拥有的块数. /* 第一步: 访问当前节点的所有子节点: 子节点有三种 第一种: 未访问过的, 我们对它进行访问, 同时设置它的时间戳dfn[u]和low[u]为++ndfn_num,以及进栈. 第二种: 访问过的,并且在栈中,我们直接更新我们 当前 节点的low[] --> 注意 应该用low[u] 和 dfn[v]比较. 第三种: 访问过的,并且不在栈中的, 我们直接跳过.因为这个时候,所以它已经染色了,属于一个连通块了. 第二步: 如果dfn[u] == low[u] 说明 已经找到一个连通块了. 这时候我们要将栈顶元素弹出,直到当前节点. 记得也要修改inSt, 同时维护我们需要的信息. */ void Tarjan(int u) { int v, i; dfn[u] = low[u] = ++dfn_num; //添加时间戳. st[++top] = u; // 进栈 inSt[u] = true; // 标示在栈 for (i=head[u]; i; i=edge[i].lst) { v = edge[i].to; if (!dfn[v]) { Tarjan(v); low[u] = min(low[u], low[v]); } else if (inSt[v]) { low[u] = min(low[u], dfn[v]); } } if (dfn[u] == low[u]) { col_num++; do { inSt[st[top]] = false; col[st[top]] = col_num; size[col_num]++; } while (st[top--] != u); } }
简单数据
/*
input:
6 8
1 3
3 5
5 6
4 6
4 1
1 2
2 4
3 4
out:
low : 1 1 3 1 6 4
col : 3 3 3 3 2 1
size: 1 1 4 0 0 0
*/
板子题: http://codevs.cn/problem/1332/