zoukankan      html  css  js  c++  java
  • tarjan复习小结

    虽然是复习,但还是学到许多。

    tarjan求强连通分量

    基础知识

    过程中遇到四种边
    1>树枝边:(dfs)搜索树上的边 满足边((u,v) ,v)不在栈中 (u)(v)的父节点
    2>前向边:与(dfs)方向一致 祖先指向子孙 没什么用
    3>后向边:与(dfs)方向相反 子孙指向祖先 满足边((u,v)). (v)在栈中,(u)(v)的祖先节点
    4>横叉边:从某个结点指向搜索树中另一子树中某结点的边 满足边((u,v)), (v)在栈中 (u)不为(v)的祖先节点

    定义两个数组(dfn)(low)(dfn[x])表示(x)节点是第几个被遍历到的。(low[x])表示(x x)以及它的所有子树的出边的(dfn)的最小值,由定义可以得出:

    如果((u,v))是树枝边 (low[u]=min(low[u],low[v]))
    如果是横叉边或后向边 (low[u]=min(dfn[v],low[u]))

    当结点(u)的搜索过程结束之后,若(dfn[u] == low[u]) 则以(u)为根的搜索子树上所有还在栈中的结点,是一个强连通分量,可退栈,为什么呢????
    我也不知道

    通俗的说,若(u)为强连通分量的根,那么它的子孙中的最高祖先应该是它本身。

    算法流程

    数组的初始化,当首次到达(u)这个点时,更新(low)(dfn)的值, 将(u)入栈
    更新(low[u])
    如果((u,v))是树枝边 (low[u]=min(low[u],low[v]))
    如果是横叉边或后向边 (low[u]=min(dfn[v],low[u]))

    如果u的子树全被遍历完,(low[u] == dfn[u])那么退栈,退到(u)退出,这些退出的元素就是一个强连通分量。

    因为图有可能有好几个部分,也就是说,(tarjan)图不连通。那么我们还要继续搜索,直到所有点都被遍历

    code

    void tarjan(int x) {
        low[x] = dfn[x] = ++cnt, sta[++top] = x, vis[x] = 1;
        for (int i = head[x]; i; i = edge[i].next) {
            int to = edge[i].to;
            if (!dfn[to]) tarjan(to), low[x] = min(low[x], low[to]);
            else if (vis[to]) low[x] = min(dfn[to], low[x]);
        }
        if (dfn[x] == low[x]) {
            num++;
            while (x != sta[top + 1]) {
                vis[sta[top]] = 0;
                top--;
            }
        }
    }
    
    for (int i = 1; i <= n; i++)
        if (!dfn[i]) tarjan(i); 
    

    模型建立

    其实就是缩点,要不然也没别的用处。

    因为每一个强连通分量中的点都是相互可达的,我们可以将当前这个强连通分量缩成一个点,这个点的权值由题目来定(通常会有强连通分量中的点权和或者点权的最小值)

    我们用到染色的思想,因为退栈的时候退栈的所有元素都是同一个强连通分量中的,所以我们可以在这个时将所有的点都染成同一种颜色,同时处理缩完点之后点的权值。

    code

    void tarjan(int x) {
        low[x] = dfn[x] = ++cnt, sta[++top] = x, vis[x] = 1;
        for (int i = head[x]; i; i = edge[i].next) {
            int to = edge[i].to;
            if (!dfn[to]) tarjan(to), low[x] = min(low[x], low[to]);
            else if (vis[to]) low[x] = min(dfn[to], low[x]);
        }
        if (dfn[x] == low[x]) {
            num++;
            while (x != sta[top + 1]) {
                vis[sta[top]] = 0;
                col[sta[top]] = num;
                val[num] += a[sta[top]];
                top--;
            }
        }
    }
    

    例题

    间谍网络
    稳定婚姻
    消息扩散
    HXY烧情侣
    受欢迎的牛
    校园网
    最大半连通子图
    网络协议
    消息的传递
    间谍网络

    tarjan求割点或桥

  • 相关阅读:
    java.lang.OutOfMemoryError: Java heap space错误及处理办法
    JQuery 引发两次$(document.ready)事件
    用Jquery动态append方式加入标签时Css样式丢失的解决方法
    操作系统第6次实验报告:使用信号量解决进程互斥访问
    操作系统实验五:文件系统
    操作系统第4次实验报告:文件系统
    操作系统第三次实验报告:管道
    操作系统第2次实验报告:创建进程
    OS第1次实验报告:熟悉使用Linux命令和剖析ps命令
    第四次实验报告:使用Packet tracer理解RIP路由协议
  • 原文地址:https://www.cnblogs.com/zzz-hhh/p/13453765.html
Copyright © 2011-2022 走看看