[leetCode]1489. 找到最小生成树里的关键边和伪关键边

题目

https://leetcode-cn.com/problems/find-critical-and-pseudo-critical-edges-in-minimum-spanning-tree/

在这里插入图片描述

Kruscal算法

先用Kruscal算法计算其中一棵最小生成树的权值v,使用并查集维护连通分量。

然后遍历每一条边,去除该边重新生成最小生成树,如果最后连通分量不为1或者权值nv > v那么这条边就是关键边,然后continue。

判断是否是伪关键边可以先将当前遍历的边使用并查集进行合并,然后并查集合并完成后如果生成树的权值nv = v那么这条边就是伪关键边。

class Solution {
    public List<List<Integer>> findCriticalAndPseudoCriticalEdges(int n, int[][] edges) {
        int m = edges.length;
        int[][] newEdges = new int[m][4];
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < 3; j++) {
                newEdges[i][j] = edges[i][j];
            }
            newEdges[i][3] = i; 
        }
        Arrays.sort(newEdges, (o1, o2)->o1[2] - o2[2]);
        UnionFind uf = new UnionFind(n);
        int v = 0;
        for (int i = 0; i < m; i++) {
            if (uf.union(newEdges[i][0], newEdges[i][1])) {
                v += newEdges[i][2];
            }
        }
        List<List<Integer>> ans = new ArrayList<>();
        ans.add(new ArrayList<>());
        ans.add(new ArrayList<>());
        for (int i = 0; i < m; i++) {
            int nv = 0;
            UnionFind uf1 = new UnionFind(n);
            for (int j = 0; j < m; j++) {
                if (j != i && uf1.union(newEdges[j][0], newEdges[j][1])) {
                    nv += newEdges[j][2];
                }
            }
            if (uf1.count != 1 || (uf1.count == 1 && nv > v)) {
                ans.get(0).add(newEdges[i][3]);
                continue;
            }

            uf1 = new UnionFind(n);
            uf1.union(newEdges[i][0], newEdges[i][1]);
            nv = newEdges[i][2];
            for (int j = 0; j < m; j++) {
                if (j != i && uf1.union(newEdges[j][0], newEdges[j][1])) {
                    nv += newEdges[j][2];
                }
            }
            if (nv == v) {
                ans.get(1).add(newEdges[i][3]);
            }
        }
        return ans;
    }

    private class UnionFind {
        int[] parent;
        int[] rank;
        int count;

        public UnionFind(int n) {
            parent = new int[n];
            rank= new int[n];
            count = n;
            for (int i = 0; i < n; i++) {
                parent[i] = i;
                rank[i] = 1;
            }
        }

        public int find(int x) {
            if (x != parent[x]) {
                parent[x] = find(parent[x]);
            }
            return parent[x];
        }

        public boolean union(int x, int y) {
            int rootX = find(x);
            int rootY = find(y);
            if (rootX == rootY) {
                return false;
            }
            if (rank[rootX] > rank[rootY]) {
                int temp = rootX;
                rootX = rootY;
                rootY = temp;
            }
            parent[rootX] = rootY;
            rank[rootY] += rank[rootX];
            count--;
            return true;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值