给定带权有向图生成最小生成树

题目:给定带权有向图生成最小生成树

思路:方法1 使用并查集按照边权值递增合并节点,直到所有节点在同一个并查集 方法2:任意节点 取相邻权值最小的边,将该边临接节点拉入已遍历集合 更新已遍历集合和未遍历集合最小权值集合,遍历完所有节点得到最小生成树

// kruskal算法求图的最小生成树
public static Set<Edge> kruskalMST(Graph graph) {
        // 图各个节点看作独立的并查集
        UnionFound240208 UF = new UnionFound240208(graph.nodes.values());
        // 将边放入优先队列 权重递增
        PriorityQueue<Edge> queue = new PriorityQueue<>(new Comparator<Edge>() {
            @Override
            public int compare(Edge o1, Edge o2) {
                return o1.weight - o2.weight;
            }
        });
        queue.addAll(graph.edges);
        // 遍历队列直到为空
        Set<Edge> ans = new HashSet<>();
        while (!queue.isEmpty()){
            Edge e = queue.poll();
            // 如果边两端是否在同一个并查集里面,如果不是将两个节点所在并查集合并为一个并查集
            if(!UF.isSame(e.from,e.to)){
                ans.add(e);
                UF.union(e.from,e.to);
            }
        }
        return ans;
    }
    // 并查集
    public static class UnionFound240208{
        private static HashMap<Node, Node> parent;
        private static HashMap<Node,Integer> sizeMap;
        UnionFound240208(Collection<Node> list){
            for (Node node : list) {
                parent.put(node,node);
                sizeMap.put(node,1);
            }
        }

        // 是否为相同并查集
        public boolean isSame(Node a,Node b){
            Node pa = findParent(a);
            Node pb = findParent(b);
            return pa == pb;
        }

        // 两个Node节点合并
        public void union(Node a,Node b){
            if(!isSame(a,b)){
                // 少数服从多数
                if(sizeMap.get(a)< sizeMap.get(b)){
                    parent.put(a,b);
                    sizeMap.put(b, sizeMap.get(a)+ sizeMap.get(b));
                    sizeMap.remove(a);
                }else{
                    parent.put(b,a);
                    sizeMap.put(a, sizeMap.get(a)+ sizeMap.get(b));
                    sizeMap.remove(b);
                }
            }
        }

        // 查找给定节点所在并查集的祖先节点
        public Node findParent(Node node){
            Node cur = node;
            ArrayList<Node> list = new ArrayList<>();
            while (cur != parent.get(cur)){
                list.add(cur);
                cur = parent.get(cur);
            }
            // 到这里 cur为node 所在并查集的祖先节点
            // 压缩list路径节点为公共祖先节点
            for (Node n : list) {
                parent.put(n,cur);
            }
            return cur;
        }

        // 多少个相互独立的并查集
        public Integer getUnions(){
            return sizeMap.size();
        }
    }
// 方法2 
public static Set<Edge> primMST240208(Graph graph) {
        Set<Node> visited = new HashSet<>();
        PriorityQueue<Edge> queue = new PriorityQueue<>(new Comparator<Edge>() {
            @Override
            public int compare(Edge o1, Edge o2) {
                return o1.weight - o2.weight;
            }
        });
        Set<Edge> ans  = new HashSet<>();

        // 最外边兜底作用,防止没有遍历所有节点
        for (Node node : graph.nodes.values()) {
            if(!visited.contains(node)){
               // 每个最小生成树初始化
                visited.add(node);
                queue.addAll(node.edges);

                while (!queue.isEmpty()){
                    Edge edge = queue.poll();
                    if(!visited.contains(edge.to)){
                        visited.add(edge.to);
                        ans.add(edge);
                        queue.addAll(edge.to.edges);
                    }
                }
            }
        }
        return ans;
    }

题目:给定图及指定节点,返回Map,key为图所有节点,value为指定节点到key代表节点的最短距离

思路:维护已遍历节点到未遍历节点的节点和最短距离映射,将最短距离关联节点纳入到已遍历节点集合,重复上面操作直到所有完成所有节点遍历

public static HashMap<Node, Integer> dijkstra240209(Node from) {
        // PC
        HashMap<Node,Integer> ans = new HashMap<>();
        HashMap<Node, Integer> disMap = new HashMap<>();
        HashSet<Node> selected = new HashSet<>();
        disMap.put(from,0);
        Node minNode = getNextNode(disMap, selected);
        if(minNode == null){
            return ans;
        }
        while (minNode != null){
            // 已遍历节点和未遍历节点的最短距离 然后加入已遍历节点集合
            selected.add(minNode);
            Integer base = disMap.get(minNode);
            // 更新已遍历节点和未遍历节点最短距离
            for (Edge edge : minNode.edges) {
                if(selected.contains(edge.to)){
                    disMap.put(edge.to,Math.min(base+edge.weight,disMap.get(edge.to)));
                }else{
                    disMap.put(edge.to,base+edge.weight);
                }
            }
            minNode = getNextNode(disMap,selected);
        }
        return disMap;
    }
    // disMap代表的是已遍历节点到未遍历节点的最小距离,key集合是已遍历节点集合子集合
    // 所以不能通过是否在disMap里面判断node是否已经遍历
    // 得到已遍历节点和未遍历节点最短edge关联的节点
    public static Node getNextNode(HashMap<Node,Integer> disMap,HashSet<Node> selected){
        int minlen = Integer.MAX_VALUE;
        Node minNode = null;
        for (Map.Entry<Node, Integer> entry : disMap.entrySet()) {
            Node node = entry.getKey();
            Integer weight = entry.getValue();
            if(!selected.contains(node) && weight<minlen){
                minNode = node;
                minlen = weight;
            }
        }
        return minNode;
    }
  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值