图的连通

来源:互联网 发布:淘宝店铺视频制作 编辑:程序博客网 时间:2024/05/22 16:04

关于判断图是否连通,一般需要先了解:
1. DFSBFS这两个搜索算法,或者说是遍历方式(实际上树的前中后序遍历和层次遍历分别就是DFS和BFS的运用)。
2. 对于图的建立此处就不在介绍了
(这里不对UnionFind在连通性的判断上做介绍。)


连通图的概念

这个链接里面,都有讲到,这个。
可能大神讲到有点抽象,小弟就做了如下图解(如有误,喷我)。
割点集与割边集
割点与桥
此外,链接中所讲的双连通分量,可以理解为连通度大于等于2的情况,也就是uv之间至少存在两条不同 的路径可达。
其中的dfs[],和low[]这两个数组可以,结合这个动图理解,这个动图。

万能模板——Tarjan

之所以我认为这个Tarjan是一个解决连通性问题的利器(厉害还是Tarjan厉害)。

/* *邻接表存储 *无向图求割点*/vector<int> G[MAXN];int dfn[MAXN], low[MAXN], keyNode[MAXN];bool vis[MAXN];void Tarjan(int u, int start, int &cnt, int &res, int &rd) {    cnt++;    dfn[u] = low[u] = cnt;    for(int i = 0; i < (int)G[u].size(); ++i) {        int v= G[u][i];        if(!vis[v]) {            Tarjan(v, start, cnt, res, rd);            if(low[v] >= dfn[u]) {                if(u != start && !vis[u])                    keyNode[res] = u, vis[u] = true, res++;                else if(u == start)                    rd++;            }            if(low[v] < low[u]) low[u] = low[v];        } else if(dfn[v] < low[u]) {            low[u] = dfn[v];        }    }}int keyVertex(int n) {    int cnt = 0, res = 0;    for(int i = 0; i <= n; ++i)        dfn[i] = 0, vis[i] = false;    for(int i = 0; i < n; ++i) {        if(!dfn[i]) {            int rd = 0;            Tarjan(i, i, cnt, res, rd);            if(rd > 1 && !vis[i])                keyNode[res] = i, vis[i] = true, res++;        }    }    return res;}
/* *邻接表存储 *无向图求割边*/struct KeySide{    int from, to;}keySide[MAXE];vector<int> G[MAXN];int dfn[MAXN], low[MAXN];void Tarjan(int u, int &cnt, int &res) {    ++cnt;    dfn[u] = low[u] = cnt;    for(int i = 0; i < (int)G[u].size(); ++i) {        int v = G[u][i];        if(!dfn[v]) {            Tarjan(v, cnt, res);            if(low[v] > dfn[u])                keySide[res].from = u, keySide[res].to = v, res++;            if(low[v] < low[u])                low[u] = low[v];        } else if(dfn[v] < dfn[u] - 1 && dfn[v] < low[u]) {            low[u] = dfn[v];        }    } } int keyEdge(int n) {    int cnt = 0, res = 0;    for(int i = 0; i <= n; ++i) dfn[i] = 0;    for(int i = 0; i < n; ++i)        if(!dfn[i])            Tarjan(i, cnt, res);    return res;}
/* *无向图求连通分支*/vector<int> G[MAXN];int dfn[MAXN], low[MAXN];stack<int> S;void Tarjan(int u, int &cnt, int &res){    low[u] = dfn[u] = ++cnt;    S.push(u);    for(int i = 0; i < (int)G[u].size(); ++i) {        int v = G[u][i];        if(!dfn[v]) {            Tarjan(v, cnt, res);            if(low[u] > low[v]) low[u] = low[v];        } else if(low[u] > dfn[v]){            low[u] = dfn[v];        }    }    if(low[u] == dfn[u]) {        int v; res++;        do{            v = S.top(), S.pop();            cout<<v<<' ';        }while(u != v);        cout<<endl;    }}void block(int n) {    int cnt = 0, res = 0;    for(int i = 0; i <= n; ++i)        dfn[i] = 0;    for(int i = 0; i < n; ++i) {        if(!dfn[i]) {            Tarjan(i, cnt, res);        }    }}
/* *有向图求连通分支*/vector<int> G[MAXN];int low[MAXN], dfn[MAXN], id[MAXN];bool inSta[MAXN];stack<int> S;void Tarjan(int u, int &cnt, int &res) {    low[u] = dfn[u] = ++cnt;    S.push(u), inSta[u] = true;    for(int i = 0; i < (int)G[u].size(); ++i) {        int v = G[u][i];        if(!dfn[v]) {            Tarjan(v, cnt, res);            if(low[u] > low[v]) low[u] = low[v];        } else if(inSta[v]) {            if(low[u] > dfn[v]) low[u] = dfn[v];        }    }    //缩点    if(low[u] == dfn[u]) {        int v; res++;        do{            v = S.top(), S.pop();            inSta[v] = false;            id[v] = res;        }while(u != v);    }}int slove(int n) {    int cnt = 0, res = 0;    for(int i = 0; i <= n; ++i)        low[i] = dfn[i] = id[i] = 0, inSta[i] = false;    for(int i = 1; i <= n; ++i)        if(!dfn[i]) Tarjan(i, cnt, res);    return res;}

就写到这吧,发现自己已经对于有向和无向的求解已经傻傻分不清了,过段时间做几道题,在看看应该能想明白。

0 0
原创粉丝点击