图的割点、割线问题

图的割点问题

邻接矩阵表示图

package com.hyl.algorithm.other;

import java.util.Arrays;

import com.hyl.algorithm.search.base.SearchIntf;
import com.hyl.algorithm.search.base.SearchIntfFactory;

/**
 * 寻找图的割点
 * <p>
 *
 * @author Hyl
 * @version V 0.1
 * @since 0.1 2020-07-01 05:15
 */
public class CutPoint implements SearchIntf {

    private ArrayGraph graph;
    private int n, m, root, start, timestamp;

    private int[] num;
    private int[] low;
    private int[] book;

    @Override
    public void init() {
        //        图
        //         1
        //      /    \
        //     4      3
        //      \    /
        //        2
        //      /   \
        //     5  -  6
        n = 6;
        m = 7;
        graph = new ArrayGraph(n);
        graph.addUndirected(1, 3, 1);
        graph.addUndirected(1, 4, 1);
        graph.addUndirected(2, 3, 1);
        graph.addUndirected(2, 4, 1);
        graph.addUndirected(2, 5, 1);
        graph.addUndirected(2, 6, 1);
        graph.addUndirected(5, 6, 1);
        num = new int[n + 1];
        low = new int[n + 1];
        book = new int[n + 1];

        root = start = 1;
        timestamp = 0;

    }

    @Override
    public void find() {
        dfs(start, root);
    }

    /**
     * 深度优先--割点算法
     * @param cur 当前结点
     * @param father 父结点
     */
    private void dfs(int cur, int father) {

        // 儿子数
        int child = 0;
        // 时间戳累加
        timestamp++;
        // 登记时间戳
        num[cur] = timestamp;
        low[cur] = timestamp;
        // 遍历连通结点
        for (int i = 1; i <= 6; i++) {
            // 判断连通
            if (graph.getPath(cur, i) == 1) {
                // 时间戳等于0表示没有被访问过
                if (num[i] == 0) {
                    // 确定父子关系,儿子数加一
                    child++;
                    // 递归
                    dfs(i, cur);
                    // 递归完成,树已经形成,子结点和当前结点中使用能访问的较小时间戳
                    low[cur] = Math.min(low[cur], low[i]);
                    // 判定是否是割点,如果不是根结点,子结点能访问最小时间戳大于等于当前时间戳
                    if (cur != root && low[i] >= num[cur]) {
                        book[cur] = 1;
                    }
                    // 如果是根结点有两个儿子,就是可以确定是割点
                    if (cur == root && child == 2) {
                        book[cur] = 1;
                    }
                } else if (i != father) {
                    // 没有搜索到就已经有时间戳了,还不是父结点,说明在没有经过父结点就已经访问过,使用最小时间戳
                    low[cur] = Math.min(low[cur], num[i]);
                }
            }
        }

    }

    @Override
    public void print() {
        graph.print();
        System.out.println(Arrays.toString(num));
        System.out.println(Arrays.toString(low));
        System.out.println(Arrays.toString(book));
    }

    public static void main(String[] args) {
        SearchIntfFactory.produce(CutPoint.class);
    }

}

图的割线问题

邻接表表示图

package com.hyl.algorithm.other;

import java.util.Arrays;

import com.hyl.algorithm.search.base.SearchIntf;
import com.hyl.algorithm.search.base.SearchIntfFactory;

/**
 * 图的割边问题
 * <p>
 *
 * @author Hyl
 * @version V 0.1
 * @since 0.1 2020-07-01 12:07
 */
public class CutLine implements SearchIntf {

    private LinkedGraph graph;
    private int n, m, start, root, timestamp;
    private int[] num, low;
    private int[][] lines;
    private int size;

    @Override
    public void init() {
        //        图
        //         1
        //      /    \
        //     4      3
        //      \    /
        //        2
        //      /   
        //     5  -  6
        n = 6;
        m = 6;
        graph = new LinkedGraph(n, m);
        graph.addUndirected(1, 3, 1);
        graph.addUndirected(1, 4, 1);
        graph.addUndirected(2, 3, 1);
        graph.addUndirected(2, 4, 1);
        graph.addUndirected(2, 5, 1);
        graph.addUndirected(5, 6, 1);
        num = new int[n + 1];
        low = new int[n + 1];

        lines = new int[m][2];
        size = 0;
        root = start = 1;
        timestamp = 0;
    }

    @Override
    public void find() {
        dfs(start, root);
    }

    private void dfs(int cur, int father) {

        timestamp++;
        num[cur] = timestamp;
        low[cur] = timestamp;

        int index = graph.first[cur];
        while (index != -1) {
            // 没有被访问过
            if (num[graph.v[index]] == 0) {
                dfs(graph.v[index], cur);
                low[cur] = Math.min(low[cur], low[graph.v[index]]);
                // 相对割点问题,>= 改为 >,表示连父节点也无法返回
                if (low[graph.v[index]] > num[cur]) {
                    lines[size][0] = cur;
                    lines[size][1] = graph.v[index];
                    size++;
                }
            } else if (graph.v[index] != father) {
                // 可以被访问到,并不是父结点
                low[cur] = Math.min(low[cur], num[graph.v[index]]);
            }

            index = graph.next[index];
        }

    }

    @Override
    public void print() {
        graph.printLines();
        System.out.println(Arrays.toString(num));
        System.out.println(Arrays.toString(low));
        for (int i = 0; i < size; i++) {
            System.out.print("(" + lines[i][0] + "," + lines[i][1] + ")\t");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        SearchIntfFactory.produce(CutLine.class);
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值