连通图小结

来源:互联网 发布:淘宝摇一摇在哪 编辑:程序博客网 时间:2024/05/21 04:18

连通图小结 A Summary for Connected Graph

Ⅰ.概念

  • 强连通
    • 强连通:有向图中(u,v)存在uv, vu的两条路径,称(u,v)为强连通
    • 强连通图:有向图中任意两个顶点强连通
    • 强连通分量:有向图的极大强连通子图
  • 弱连通
    • 弱连通:无向图中(u,v)存在uv的路径,称(u,v)为弱连通
    • 弱连通图:无向图中任意两个顶点弱连通,(可以将忽略方向的有向图看作无向图)
    • [弱]连通分量:无向图的极大[弱]连通子图
  • 割点与桥
    • 割点:无向图中点u,删去后连通分量数目增加(连通图则使得图不再连通),称u为割点
    • 桥:无向图中边(u,v),删去后连通分量数目增加(连通图则使得图不再连通),称(u,v)为桥(割边)
  • 点双连通
    • 点双连通:无向图中(u,v)存在至少两条“点不重复”的路径,称(u,v)为点双连通
      这个要求等价于任意两条边都在同一个简单环中,即内部无割点
    • 点双连通分量:无向图的极大点双连通子图。
    • 性质:
      • 无向图每条边恰好属于一个点双连通分量
      • 不同的点双连通分量之间可能会有公共点,最多只有一个且一定是割点
      • 任意割点都是至少两个不同点双连通分量的公共点
  • 边双连通
    • 边双连通:无向图中(u,v)存在至少两条“边不重复”的路径,称(u,v)为边双连通
      这个要求低一点,只需要每条边都至少在一个简单环中,即所有的边都不是桥
    • 边双连通分量:无向图的极大边双连通子图。
    • 性质:
      • 除桥不属于任何边双连通分量外,其他每条边恰好属于一个边双连通分量
      • 把所有桥删除后,每个连通分量对应原图的一个边双连通分量

Ⅱ.连通图算法

  • 连通分量 Connected Component
    求解连通分量只需要dfs或者bfs把图搜一遍就好了,当然并查集也是可以的。
    一般不爆栈的情况,dfs好写适用性强
//Connected Componentsvector<int> G[N];int id[N], cc;void dfs(int u) {    id[u] = cc;    for(int v : G[u]) {        if(id[v]) continue;        dfs(v);    }}void findCC() {    cc = 0;    for(int i = 1; i <= n; ++i) {        if(id[i]) continue;        ++cc;        dfs(i);    }}
  • 割点 Cut
    基于dfs时间戳的Tarjan算法
    dfn[u]:= u的时间戳,low[u]:= u及其后代能连回的最早的祖先的时间戳
    如果low[v]dfn[u],即v及其所在的子树都没有后向边(back edge)连回u的祖先
    如果删去u,那么u的祖先与v及其所在的子树不连通,根据“连通”关系的传递性,整个图就不连通了
//Tarjan-cutvector<int> G[N];int dfn[N], low[N], cut[N], dfsNum;void tarjan(int u, int f) {    dfn[u] = low[u] = ++dfsNum;    int son = 0;    for(int v : G[u]) {        if(v == f) continue;        if(!dfn[v]) {            ++son;            tarjan(v, u);            low[u] = min(low[u], low[v]);            if(low[v] >= dfn[u]) cut[u] = true;        } else low[u] = min(low[u], dfn[v]);    }    if(f < 0 && son == 1) cut[u] = false;}void init() {    dfsNum = 0;    memset(dfn, 0, sizeof dfn);    memset(cut, false, sizeof cut);    tarjan(root, -1);}
  • Bridge
    基于dfs时间戳的Tarjan算法
    dfn[u]:= u的时间戳,low[u]:= u及其后代能连回的最早的祖先的时间戳
    如果low[v]>dfn[u],即v及其所在的子树只能连回v自己
    如果删去(u,v),那么uv及其所在的子树不连通,根据“连通”关系的传递性,整个图就不连通了
//Tarjan-bridgevector<int> G[N];vector<pair<int, int> > bridge;int dfn[N], low[N], dfsNum;void tarjan(int u, int f) {    dfn[u] = low[u] = ++dfsNum;    for(int v : G[u]) {        if(v == f) continue;        if(!dfn[v]) {            tarjan(v, u);            low[u] = min(low[u], low[v]);            if(low[v] > dfn[u]) bridge.push_back({u, v});        } else low[u] = min(low[u], dfn[v]);    }}void init() {    dfsNum = 0;    bridge.clear();    memset(dfn, 0, sizeof dfn);    tarjan(root, -1);}
  • 点双连通分量 Biconnected Component or Block
    基于dfs时间戳的Tarjan算法
    dfn[u]:= u的时间戳,low[u]:= u及其后代能连回的最早的祖先的时间戳
vector<int> G[N];int dfn[N], low[N], cut[N], bcc, dfsNum;vector<int> block[N];int stk[N], top;void tarjan(int u, int f) {    dfn[u] = low[u] = ++dfsNum;    stk[++top] = u;    int son = 0;    for(int v : G[u]) {        if(v == f) continue;        if(!dfn[v]) {            ++son;            tarjan(v, u);            low[u] = min(low[u], low[v]);            if(low[v] >= dfn[u]) {                cut[u] = true;                block[++bcc].push_back(u);                while(true) {                    int x = stk[top--];                    block[bcc].push_back(x);                    if(x == v) break;                }            }        } else low[u] = min(low[u], dfn[v]);    }    if(f < 0 && son == 1) cut[u] = false;}void init() {    bcc = dfsNum = 0;    memset(dfn, 0, sizeof dfn);    memset(cut, 0, sizeof cut);    tarjan(root, -1);}
  • 边双连通分量 Edgebiconnected Component
    基于dfs时间戳的Tarjan算法
    dfn[u]:= u的时间戳,low[u]:= u及其后代能连回的最早的祖先的时间戳
    边双连通缩点其实就是留下桥,把所有桥边构成了新图,新图是一棵树
//Tarjan-bccvector<int> G[N];int dfn[N], low[N], in[N], id[N], bcc, dfsNum;int stk[N], top;void tarjan(int u, int f) {    dfn[u] = low[u] = ++dfsNum;    stk[++top] = u;    in[u] = true;    for(int v : G[u]) {        if(v == f) continue;        if(!dfn[v]) {            tarjan(v, u);            low[u] = min(low[u], low[v]);        } else low[u] = min(low[u], dfn[v]);    }    if(low[u] == dfn[u]) {        ++bcc;        while(true) {            int v = stk[top--];            in[v] = false;            id[v] = bcc;            if(v == u) break;        }    }}void init() {    bcc = dfsNum = 0;    memset(dfn, 0, sizeof dfn);    tarjan(root, -1);}
0 0
原创粉丝点击