Orz LRJ
因为都是街货,为了防止大牛D,所以仅结合资料作简单总结
联通分量:u -> v, v -> u,相互可达的节点称为连通分量
DFS一遍即可,也可用并查集去判联通块
割点
无向图G中,删除某点u后,若联通分量数目增加,则u为此图G中的一个割点。这意味着若在连通图中删除割点,则图变得不连通。
DFS整个图,利用时间戳打下标记,可以得到定理:非根节点u是图G的割点当且仅当u存在一个子节点v,使得v及其后代都没有反向边连向u的祖先(不包括u)。DFS森林的性质对于此定理的正确性而言极其重要!若令low[u]为u及其后代所能连回的最早的祖先的dfn值(时间戳),定理又可表述为:非根节点u是图G的割点当且仅当u存在一个子节点v,使得low[v]>=dfn[u]。
我的模板(特判相对比较优美)
int dfs(int u, int father)
{
int lowu = dfn[u] = ++dfstime, lowv, child = 0;
for (int i = 0, v; i < (int) g[u].size(); ++i)
{
if (!dfn[v = g[u][i]])
{
++child, lowu = Min(lowu, lowv = dfs(v, u));
if (lowv >= dfn[u]) ic[u] = 1;
}
else if (dfn[v] < dfn[u] && v != father)
lowu = Min(lowu, dfn[v]);
}
if (father < 0 && child == 1) ic[u] = 0;
return dfn[u] = lowu;
}
int main()
{
for (int u = 1; u <= n; ++u)
if (!dfn[u]) dfs(u, -1);
for (int i = 1; i <= n; ++i)
if (ic[i]) ++icnum;
printf("%d\n", icnum);//icnum为割点个数
return 0;
}
割边
DFS森林的基础上,若v的后代只能连回v自己,(即low[v]>dfn[u]),那么(u,v)其实就是割边,即删除此边则图G联通分量数目增加,连通图变得不连通。
强连通分量
极大强连通子图。如果把每个强连通分量缩成一个点,可知缩点后的新图必然是有向无环图。
每个强联通分量都是树的一棵子树。可以将问题转化为判断一个点是否为一个强联通分量中最先被发现的点。
我的模板
void dfs(int u)
{
dfn[u] = low[u] = ++dfstime; S.push(u);
for (int i = 0, v; i < (int) g[u].size(); ++i)
{
if (!dfn[v = g[u][i]]) dfs(v), low[u] = Min(low[u], low[v]);
else if (!toscc[v]) low[u] = Min(low[u], dfn[v]);
}
if (low[u] == dfn[u])
for (++scctot; ; )
{
int x = S.top(); S.pop();
toscc[x] = scctot;
if (x == u) break;
}
}
int main()
{
for (int i = 1, u, v; i <= m; ++i)
g[u = getint()].push_back(v = getint());
for (int i = 1; i <= n; ++i)
if (!dfn[i]) dfs(i);
printf("%d\n", scctot);
return 0;
}
点双连通分量
任意两点至少存在两条“点不重复”的路径,则此连通图是点-双连通的(一般称双连通),意味着任意的两条边都是在同一个简单环上,即内部无割顶。点-双连通的极大子图叫做双连通分量或块。定理:不同双联通分量最多只有一个公共点,且它一定是割顶,任意割顶都是至少两个不同双连通分量的公共点。
边双连通分量
任意两点至少存在两条“边不重复”的路径,则此连通图是边-双连通的。意味着只需要每条边都至少在一个简单环中,即所有边都不是桥。边-双连通的极大子图叫做边-双连通分量,除了桥不属于任何边-双连通分量之外,其他每条边恰好属于一个边-双连通分量,而且把所有桥删除之后,每个联通分量对应原图中的一个边-双连通分量。
推荐GJB的几篇文章
http://www.byvoid.com/blog/scc-tarjan/ 有向图强联通分量法的Tarjan算法
http://www.byvoid.com/blog/biconnect/ 图的割点、桥与双联通分支
缩点
联系上文易知共有三类缩点
将每个强连通分量缩成一个点
将每个点双连通分量缩成一个点
将每个边双连通分量缩成一个点
缩点过程其实只要把DFS求上面三种东西的过程稍作修改即可
比如求强连通分量时,我的模板每个强连通分量缩成的点即为退栈时的SCCTOT
而toscc就是由原图中点指向新图中点的映射
若需要重新建图,则for每条边看两点是否在同一强连通分量中,否则就在新图中添加一条新边
PS:2-SAT问题可以利用缩点!