佬们能帮我看看这个用Kruskal算法求最小生成树的java代码哪里出错了吗?
  • 板块题目总版
  • 楼主Mr_Jyx
  • 当前回复1
  • 已保存回复1
  • 发布时间2024/1/18 11:59
  • 上次更新2024/1/18 16:32:02
查看原帖
佬们能帮我看看这个用Kruskal算法求最小生成树的java代码哪里出错了吗?
121758
Mr_Jyx楼主2024/1/18 11:59

题目链接:P3366 MST

思路是利用Union-Find并查集和PriorityQueue来实现Kruskal算法求最小生成树

判断图是否连通部分isConnected()是利用BFS算法遍历所有数据点判断图是否连通

数据点总是过不了 7个WA 3个MLE 3个AC

以下是java代码:

import java.util.*;

class UnionFind {

    private final int[] elements;

    public UnionFind(int size) {
        elements = new int[size];
        for (int i = 0; i < elements.length; i++) {
            elements[i] = i;
        }
    }

    public int find(int i) {
        while (elements[i] != i) {
            i = elements[i];
        }
        return i;
    }

    public void union(int i, int j) {
        elements[find(i)] = find(j);//i的祖宗的祖宗是j的祖宗
    }
}






class Edge implements Comparable<Edge> {
    public final int i, j, weight;

    public Edge(int i, int j, int weight) {
        this.i = i;
        this.j = j;
        this.weight = weight;
    }


    @Override
    public int compareTo(Edge o) {return weight - o.weight;}
}



public class Main {
    static boolean isConnected(int[][] graph){ //点1,2,...,vertices
        int count = 1;
        //从1开始找
        //假设0是无路
        int currentNode = 0;
        Queue<Integer> queue = new LinkedList<>();
        boolean[] visited = new boolean[graph.length];
        for (int i = 0; i < graph.length; i++) {
            visited[i] = false;
        }

        queue.offer(0);
        visited[0] = true;
        while(!queue.isEmpty()){
            currentNode = queue.poll();
            for (int i = 0; i < graph.length; i++) {
                if(graph[currentNode][i] != Integer.MAX_VALUE && !visited[i]){
                    queue.offer(i);
                    visited[i] = true;
                    count++;
                }
            }
        }

        if(count == graph.length){
            return true;
        } else {
            return false;
        }
    }
  
    private static final int INF = Integer.MAX_VALUE;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        int M = sc.nextInt();
        int[][] map = new int[N][N];
        for (int i = 0; i < N; i++) {
            Arrays.fill(map[i], Integer.MAX_VALUE);
        }
        for (int i = 1; i <= M; i++) {
            int s = sc.nextInt();
            int d = sc.nextInt();
            map[s-1][d-1] = sc.nextInt(); //表示的是点s到点d的距离
            map[d-1][s-1] = map[s-1][d-1];
        }
        if(isConnected(map)){
            System.out.println(kruskal(map));
        } else {
            System.out.println("orz");
        }
    }

    public static int kruskal(int[][] map) {
        /**
         * 并查集,检测两个点是否已经属于同一棵树
         */
        UnionFind unionFind = new UnionFind(map.length); //n^2大小的邻接矩阵 其包含n个点的信息
        /**
         * 待选择的边,放入优先队列排序
         */
        Queue<Edge> edgeQueue = new PriorityQueue<>();
       
        for (int i = 0; i < map.length; i++) {
            for (int j = 0; j < i; j++) {
                if(map[i][j] != INF){
                    edgeQueue.offer(new Edge(i,j,map[i][j]));
                }
            }
        }
        /**
         * 总路径长度
         */
        int sum = 0;
        /**
         * 当前已选择边的数量
         */
        int count = 0;
        while (count < map.length - 1) { //map.length是总点数 总点数-1是边数 但当前 边数=总点数-1 时表示边已经选完 不用再选 于是是小于号
            Edge edge = edgeQueue.poll();
            /**
             * 检测边的两个顶点是否已经在同一棵树中
             */
            if (unionFind.find(edge.i) == unionFind.find(edge.j)) {
                continue;
            }
            count++;
            sum += edge.weight;
            /**
             * 将两个顶点所在的树在并查集中合并
             */
            unionFind.union(edge.i, edge.j);
        }
        return sum;
    }
}
2024/1/18 11:59
加载中...