最小生成树---Kruskal算法

本文介绍了最小生成树的概念,以及其在城市规划和类似问题中的应用。主要讨论了Prim算法和Kruskal算法,并以计算机网络连接问题为例,展示了如何使用这些算法求解最小连接费用。
摘要由CSDN通过智能技术生成

最小生成树定义:

        给定一张边带权的无向图 G=(V,E),其中 V 表示图中点的集合,E 表示图中边的集合。

        由 V 中的全部 n 个顶点和 E 中 n−1 条边构成的无向连通子图被称为 G 的一棵生成树,其中边的权值之和最小的生成树被称为无向图 G 的最小生成树。

最小生成树应用场景:

        例如在城市规划中,有 n 座城市,需要修建高速公路来连通各个城市,如何设计可使得路程修建总距离最短。可以抽象为,当前有个 n 个点的无向图,每个点之间都有一条连线,从中找出 n-1 条边,使得所有的点都在一个集合中,且集合中所有边的权值加起来最小。

        也可广泛的应用于通信,电路,航线等等类似的问题。

最小生成树其他算法 最小生成树---朴素Prim算法,堆优化版Prim算法-CSDN博客


 Kruskal算法

使用到并查集并查集(基本原理+示例)-CSDN博客 

算法思路:

S:已加入最小生成树的点的集合

伪代码:

1.将所有的边按权重从小到大进行排序(点之间是双向的,但只需要存储一个方向的边)

2.枚举每一条边 a -> b 权重c

        if a,b不联通

                将这条边加入集合S (使用到并查集的方法)

 最小生成树的题(都来源acwing):

1138. 城市公交网建设问题 - AcWing题库 (数据范围小,prim也可使用)

1147. 构造完全图 - AcWing题库

最小生成树的 题库 - AcWing

例题:  1139. 最优布线问题 - AcWing题库

学校有 n 台计算机,编号是 1∼n,为了方便数据传输,现要将它们用数据线连接起来,同一条数据线中数据的传输可以是 双向 的。

两台计算机被连接是指它们有数据线连接。

由于计算机所处的位置不同,因此不同的两台计算机的连接费用往往是不同的。

当然,如果将任意两台计算机都用数据线连接,费用将是相当庞大的。

为了节省费用,我们采用数据的间接传输手段,即一台计算机可以间接的通过若干台计算机(作为中转)来实现与另一台计算机的连接。

现在由你负责连接这些计算机,任务是使任意两台计算机都连通(不管是直接的或间接的)。

输入格式

第一行为整数 n,表示计算机的数目。

此后的 n 行,每行 n 个整数,输入一个对角线上全部是0的 对称矩阵
其中第 x+1 行 y 列的整数表示直接连接第 x 台计算机和第 y 台计算机的费用。

输出格式

一个整数,表示最小的连接费用。

数据范围

2≤n≤100,
连接任意两台计算机的费用均是非负整数且不超过10000。

输入样例:

3
0 1 2
1 0 1
2 1 0

输出样例:

2
import java.io.*;
import java.util.*;

class Main{
    static int N = 110;
    static int n,m,res;
    static int[] p = new int[N];
    static Queue<PII> q = new PriorityQueue<>();
    public static void main(String[] args) throws IOException{
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        n = Integer.parseInt(in.readLine());
        for(int i=1;i<=n;i++){
            p[i] = i; // 初始化p[],一个点一个集合
            String[] s = in.readLine().split(" ");
            for(int j=1;j<i;j++){
                q.add(new PII(i,j,Integer.parseInt(s[j-1]))); // 只读取左下半的数据
            }
        }
        
        // kruskal算法
        while(!q.isEmpty()){ // 读取所有的边
            PII t = q.poll();
            int a = t.a, b = t.b, c = t.c;
            if(find(a)!=find(b)){ // 如果不在一个集合
                p[find(a)] = find(b); // 加到一个集合
                res += c; // 加上权重
            }
        }
        
        System.out.println(res);
    }
    // 找集合的根节点
    public static int find(int u){
        if(p[u]!=u) p[u] = find(p[u]);
        return p[u];
    }
}
// 存储边
class PII implements Comparable<PII>{
    int a;
    int b;
    int c;
    public PII(int a,int b,int c){
        this.a = a;
        this.b = b;
        this.c = c;
    }
    public int compareTo(PII i){
        return this.c-i.c;
    }
}

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值