图论学习笔记——强连通分量/双连通分量

预备知识

  • 强连通:对于图\((V,E)\)上的两个顶点\(u,v\),若存在从\(u\)\(v\)的有向路径,同时也存在从\(v\)\(u\)的有向路径,(注意有路径即可,也就是允许有中间顶点)则称这两个顶点强连通。
  • 强连通图:若图\((V,E)\)上的任意两个顶点都强连通,则称这个图为强连通图。
  • 强连通分量:有向图的极大强连通子图

强连通分量(SCC,Strongly Connected Components)

求强连通分量(Tarjan算法)

\(dfn[i]:=\) 顶点\(i\)在搜索过程中的次序编号(时间戳),即记录顶点\(i\)是第几个被搜索到的顶点。

\(low[i]:=\) 顶点\(u\)及其后代顶点所能追溯到的最早的顶点(即祖先顶点)\(v\)的时间戳\(dfn[v]\)。当顶点\(u\)第一次被搜索到时,初始化为low[i]=dfn[i].

int dfs_clock, scc_cnt;
int dfn[maxn], low[maxn], sccno[maxn];

void dfs(int u) {
    dfn[u] = low[u] = ++dfs_clock;
    //给顶点u打上时间戳
    s.push(u);
    for (int i = head[u]; i; i = e[i].next) {
        int v = e[i].to;
        if (!dfn[v]) {
            //顶点v还没被搜索到
            dfs(v);
            low[u] = min(low[u], low[v]);
            //维护祖先中最小的时间戳
        }
        else if (!sccno[v]) {
            low[u] = min(low[u], dfn[v]);
            //顶点v已经被搜索过了,但还不属于某一个SCC
        }
    }
    //对顶点u的所有后代顶点完成搜索之后
    //开始判断顶点u是不是这个强连通分量中第一个出现的顶点
    if (low[u] == dfn[u]) {
        scc_cnt++;
        //SCC数量+1
        while (1) {
            int x = s.top(); s.pop();
            sccno[x] = scc_cnt;
            //给分量中的所有顶点记录所在SCC的编号
            if (x == u) break;
            //访问完u之后,就完成了对这个SCC所有顶点的访问,跳出
        }
    }
}

void find_scc(int n) {
    dfs_clock = scc_cnt = 0;
    mem(sccno, 0);
    mem(dfn, 0);
    for (int i = 1; i <= n; i++) {
        if (!dfn[i]) dfs(i);
    }
}

缩点

顾名思义,将图中的强连通分量看作是一个点,就是缩点。同时原图变为一个DAG,如此便可以将一个有环的图转化为DAG,可以利用DAG的性质解决问题。

问题一:给定一个有向图\((V,E)\),包含\(n\)个点和\(m\)条边,问至少还要再添加多少条边才能使整个图变成强连通图。

对于DAG,这个问题的答案是\(max(a,b)\),其中\(a\)是入度为零的顶点个数,\(b\)是出度为零的顶点个数。特别地,如果DAG中只有一个点,则答案为0。但问题中给出的图不一定无环,此时就可以用缩点的方法将图转化为DAG。

问题二:给定一个有向图\((V,E)\),包含\(n\)个点和\(m\)条边,每个点有一个权值。求一条路径,使得路径上点的权值和最大。允许多次经过一条边或一个点,但权值只计算一次。

对于DAG,这个问题就是求DAG上的最长路,用DAG上的dp即可解决。定义\(dp[i]\)为从顶点\(i\)出发的路径的最大权值和,则转移方程为\(dp[i]=max(dp[i],dp[j]+val[i])\),其中顶点\(j\)满足:存在\(i→j\)的有向边。

需要注意的是,在方程中需要先求出\(dp[j]\),才能用它来更新\(dp[i]\)。具体代码实现有两种方法:

  1. 记忆化搜索;
  2. 先求图的拓扑排序,再以拓扑排序的倒序进行dp。

题目给定的图可能有环,只需对原图求强连通分量,缩点,建立新图,则新图就是DAG。

posted @ 2020-10-14 18:20  StreamAzure  阅读(389)  评论(0编辑  收藏  举报