图的关节点算法实现

关节点:可以将一个连通分量分割成两个或多个连通分量的点。
重连通图:没有关节点的图,在重连通图中任意两点之间至少存在两条路径

关节点求法:算法较难理解,算法结合了先序深度搜索和后序深度搜索,先序深度搜索确定每个点访问的顺序,而后序深度搜索则根据先序计算的顺序确定关节点。具体递归算法步骤:
递归算法: 递归算法中,第一部分为记录结点访问次序,中间部分为调用递归函数访问子节点,第三部分为根据递归函数的退出,来确定结点的回边。
1.从vi开始,调用递归算法
2.一直递归到某个点s(该没有未被访问的邻接点),这个点有两种状况,第一种是没有回边,只有一条指向双亲的边,则记录该结点的回边值为该结点的双亲的访问顺序值,第二种是有回边,则记录该点回边值为指向最先访问的祖先的访问顺序值,退出递归函数
3.从第二步退出递归函数后,如果s结点为无回边状况,则判断s的父节点为关节点,如果为有回边状况,则s结点的回边值肯定小于双亲的访问顺序值,则将双亲的回边值也更新为该值。
4.重复2,3步骤。
在这里插入图片描述
在这里插入图片描述

代码实现:

/**
     * @name 得到关节点
     * @use 获得图的关节点,图用矩阵(二维数组)表示
     * @param chart
     * @param start 起始结点
     * @return points
     */
    public static function getKeyPoint($chart, $start = 0) {
        $points = array($start);//已访问的结点
        $visited = array($start => 1);//各节点的访问顺序
        $low = array();//各节点的回边值
        $count = 1;
        $T = array();//保存关节点
        $temp = true;
        foreach ($chart[$start] as $key => $value) {
            if ($value !== 0 && !in_array($key, $points)) {
                self::getKeyPointDFS($chart, $key, $points, $visited, $low, $count, $T);
                if ($count < count($chart) && $temp) {
                    $T[] = $start;
                    $temp = false;
                }
            }
        }
        return $T;
    }
    public static function getKeyPointDFS($chart, $start, &$points,&$visited, &$low, &$count, &$T) {
        $points[] = $start;
        $visited[$start] = $min = ++$count;
        foreach ($chart[$start] as $key => $value) {
            if ($value == 0) {
                continue;
            }
            if (!in_array($key, $points)) {
                self::getKeyPointDFS($chart, $key, $points, $visited, $low, $count, $T);
                if ($low[$key] < $min) $min = $low[$key];
                if ($low[$key] >= $visited[$start]) $T[] = $start;
            } else if($visited[$key] < $min) {
                $min = $visited[$key];
            }
        }
        $low[$start] = $min;
    }

猜你喜欢

转载自blog.csdn.net/qq_25744595/article/details/84564393