P3366 【模板】最小生成树 ( Kruskal 克鲁斯卡尔 )

洛谷: P3366 【模板】最小生成树

在这里插入图片描述


最小生成树解决问题: 如何用最小的代价,用n-1条边连接n个点的问题.
在最小生成树中,我们需要用到并查集中的 find 和 join。


思路: 求最短,自然考虑到贪心,首先选择最短的边, 次短……重复选择权值较小的边,直到选出了n-1条边,使n个点连通。

注意: 在选择的过程中必须排除掉会构成回路的边。

方案: 排序+贪心+并查集


算法流程:

1、将数据按权值排序,我们在离散的顶点中慢慢增加边,构造并查集 fa[n]。

2、选择权值最小的边(x1,y1),增加到图中。这条边的两个端点(x1,y1)被选中到最小生成树中,两个顶点彼此连通了,在并查集中合并(x1,y1)。

3、选择权值次小的边,首先判断这条边的增加是否构成回路,是否在同一集合:否 增加这条边,在并采集中合并(xi,yi);是 跳过这条边。

4、反复执行步骤3,直到选出n-1条边将n个点连通。

扫描二维码关注公众号,回复: 12283537 查看本文章


AC Code

可能是 edge 类的问题,不开启O2优化一直卡第9样例的内存, 开启O2优化后概率过

import java.util.*;
import static java.lang.System.out;

public class Main{
    
    
    
    // 边
    static class edge implements Comparable<edge>{
    
    
        int f;
        int t;
        int c;
        public edge(int f, int t, int c){
    
    
            this.f = f;
            this.t = t;
            this.c = c;
        }
        
        public int compareTo(edge e) {
    
    
            return this.c - e.c;
        }
    }
    
    static int[] fa = new int[5007];
    
    public static int findset(int x) {
    
    
        if(x == fa[x]) return x;
        return fa[x] = findset(fa[x]);
    }
    
    public static void union(int x, int y) {
    
    
        int rootx = findset(x);
        int rooty = findset(y);
        if(rootx != rooty) fa[rootx] = rooty;
    }
    
    public static void main(String[] args) {
    
    
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int m = in.nextInt();
        edge[] e = new edge[m];
        for(int i = 0; i < m; i++) {
    
    
            int a = in.nextInt();
            int b = in.nextInt();
            int c = in.nextInt();
            // 1 <= n <= 5000
            e[i] = new edge(a - 1, b - 1, c);
        }
        // 按权值从小到大排序
        Arrays.sort(e);
        
        // 初始化
        for(int i = 0; i < n; i++) fa[i] = i;
        
        int cnt = 0, ans = 0;
        // 选 n - 1 条边将 n 个顶点连接起来就行
        for(int i = 0; i < m; i++) {
    
    

            // 已经是连通状态, 再连接就会成环
            if(findset(e[i].f) == findset(e[i].t)) continue;
            
            // 连通
            union(e[i].f, e[i].t);
            ans += e[i].c;
            cnt++;

            // 完成
            if(cnt == n - 1) {
    
    
                out.println(ans);
                return ;
            }
            
        }
        
        out.println("orz"); 
    }
    
}



猜你喜欢

转载自blog.csdn.net/qq_43765535/article/details/112800946