最小生成树 - Kruskal算法

一、题目描述:

给出一个无向图,求出最小生成树,如果该图不连通,则输出 orz

输入格式

第一行包含两个整数 N,MN,M,表示该图共有 N 个结点和 M 条无向边。

接下来 M 行每行包含三个整数 Xi​,Yi​,Zi​,表示有一条长度为 Zi​ 的无向边连接结点 Xi​,Yi​。

4 5
1 2 2
1 3 2
1 4 3
2 3 4
3 4 3

输出格式

如果该图连通,则输出一个整数表示最小生成树的各边的长度之和。如果该图不连通则输出 orz

7

二、思路分析:

  1. 什么是最小生成树?

就是将图中的顶点全部连接起来(任意两个顶点能够连接),使连接起来的边权值最小。这里注意连接起来的顶点不可能成环(没有意义嘛),因此n个顶点连接,边的个数应该是n-1

  1. Kruskal?

Kruskal(克鲁斯卡尔)算法是最小生成树是经典算法之一,基于贪婪算法的思想,优先选择权值最小的边连接两个顶点,针对边,对于稀疏图(边数少)时更好。 但是连接的时候我们需要进行判断,判断这个两个顶点是否已经通过其他顶点连接,如果它们已经连接就丢弃(没有意义嘛)。如果说这两个顶点没有连接,那么就把它们两个连接起来,把与这两个顶点相关的顶点也连接(把它们记录下来),这里使用到了并查集记录。

三、AC 代码:

import java.util.*;
public class Main {
    // f[] 记录这个顶点的集合头头(判断两个顶点是否连接)
    static int f[];
    static int n;

    public static void main(String[] args) {
        Scanner sr = new Scanner(System.in);
        n = sr.nextInt();       //结点
        int m = sr.nextInt(); //无向边
        f = new int[n + 1];
        // 创建大小是m的Node 数组(刚好会比较好,不然不好排序)
        Node node[] = new Node[m];
        // 初始化,每个顶点的祖先都是自己
        for (int i = 1; i <= n; i++)
            f[i] = i;

        for (int i = 0; i < m; i++) {
            int x = sr.nextInt();
            int y = sr.nextInt();
            int z = sr.nextInt();
            node[i] = new Node(x, y, z);
        }

        // 排序,根据边的权值从小到大排列
        Arrays.sort(node, new Comparator<Node>() {
            @Override
            public int compare(Node o1, Node o2) {
                return o1.weight - o2.weight;
            }
        });

        int count = 0, ans = 0;
        for (Node temp : node) {
            // 边的个数是n-1 说明n个顶点连接起来了,就可以直接输出结果了
            if (count == n - 1) break;
            
            int xx = find(temp.from); 
            int yy = find(temp.to);
            // 如果它们的祖先不一样, 说明from顶点 和 to顶点没有连接
            if ( xx != yy ) {
            	f[xx] = yy;
                ans += temp.weight;
                count++;
            }
        }
        
        if (count == n - 1) {
            System.out.println(ans);
        } else System.out.println("orz");
    }


    //找祖先并统一祖先
    static int find(int x) {
        if (x == f[x]) return x;
        return f[x] = find(f[x]);
    }

    static class Node {
        int from, to, weight;
        Node(int from, int to, int w) {
            this.from = from;
            this.to = to;
            this.weight = w;
        }
    }
}

四、总结:

Kruskal写最小生成树还是很好理解的,主要就是对边从小到大进行排序,依次取,看看对现在的图有没有用,有用就放上去,并改变能通过这条边进行连接的顶点,当放上去n-1条边,最小生成树也就完成了

posted @ 2022-03-16 11:26  人生的激活码  阅读(19)  评论(0编辑  收藏  举报