有向图强联通分量的Tarjan算法
算法内容
d f n [ u ] dfn[u] dfn[u] :节点 u u u 搜索的次序编号
l o w [ u ] low[u] low[u] :节点 u u u 或 u u u 的子树(经过最多一条后向边或栈中横叉边)能回溯到的最早的栈中节点的次序编号
void Tarjan(int u){
dfn[u]=low[u]=++idx;
ins[u]=true,stk[++top]=u;
for(int i=0;i<e[u].size();++i){
int v=e[u][i];
if(!dfn[v]){
Tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(ins[v]) low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){
num[bel[u]=++sum]=1,ins[u]=false;
int v=-1;
while(v=stk[top--],v!=u){
++num[bel[v]=sum];
ins[v]=false;
}
}
}
POJ 2186
考虑将图中的强连通分量缩点后构造新图,答案就是出度为零的强连通分量里包含的点数,注意存在两个出度为零的强连通分量时则无解。
POJ 3180
本质上就是找包含点数大于等于 2 2 2 的强连通分量的个数。
POJ 1236
第一个问题就是求缩点后入度为零的强联通分量的个数。
第二个问题我们可以考虑树的情况,比较显然就是入度为零和出度为零的点数的最大值,考虑扩展到森林的情况,将第一个树的出度为零的点连入第二个树入度为零的点,依次类推,最后将最后一棵树连回第一棵树,可以证明这样需要的边数最少。