目录

纯个人整理,蓝桥杯使用的算法模板day4(图论 最小生成树问题),手打个人理解注释,超全面,且均已验证成功(附带详细手写“模拟流程图”,全网首个

目录

最小生成树

最小生成树:在无向图中求一棵树(n-1条边,无环,连通所有点),而且这棵树的边权和最小

(ps:可能结果不止一种)

Prim

算法思路

Prim算法从一个顶点开始,每次选择与顶点权重最小的边。("点"为核心,适合稠密图,因为稠密图"边"多)

附带Prim模拟流程图 ,实际有两个解,具体可看文章最后,但两个解顶点权重总和相同,因此求出一种结果即可,保证实际应用绝对正确,大家也可学习作者是如何进行模拟,期待能够帮助你

(ps:最小生成树模拟量过于庞大,模拟了整整四页,有部分涂改,请见谅,但可保证改正后的一定正确,因此读者可主要看prim算法,另一个算法写的过于繁杂)

看在作者完整模拟的份上,可以求个赞、收藏与关注(比心)

代码

java 复制代码
import java.util.Arrays;

public class PrimMST {
    // 定义无穷大常量(用MAX_VALUE的一半防止加法溢出)
    private static final int INF = Integer.MAX_VALUE / 2;

    public static int prim(int[][] graph) {
        int n = graph.length;        // 图的顶点数量
        int[] dist = new int[n];     // 存储各顶点到最小生成树(MST)的最小距离
        boolean[] visited = new boolean[n]; // 标记顶点是否已加入MST
        Arrays.fill(dist, INF);      // 初始化所有距离为无穷大
        
        dist[0] = 0;                 // 从顶点0开始,到自身的距离为0
        int totalWeight = 0;         // MST的总权重
        
        // 需要选择n个顶点加入MST
        for (int i = 0; i < n; i++) {
            // 步骤1:找到未访问顶点中距离MST最近的顶点u,若找到,则添加进最小生成树(如i=4时,只剩V2与V5未访问过,并且此时dist = [0, 5, 1, 4, ,6 , 2],dist[1](V2)到最小生成树的距离为5,dist[4](V5)到最小生成树的距离为6,因此最近的顶点为V2,并添加进最小生成树中)
            int u = -1; // 初始化为-1表示未找到
            for (int j = 0; j < n; j++) {
                // 如果顶点j未访问,且(u未改变 或 j的距离更小)
                if (!visited[j] && (u == -1 || dist[j] < dist[u])) {
                    u = j; // 更新最近顶点
                }
            }
            
            // 如果最近顶点的距离仍是INF,说明图不连通
            if (dist[u] == INF) return -1;
            
            visited[u] = true;       // 标记u已加入MST
            totalWeight += dist[u];  // 累加边权重
            
            // 步骤2:更新u的邻接顶点到MST的最短距离(如从顶点V1开始时,到顶点V2的距离是6,但i=1的遍历中,找到最近顶点为V3时,此时最小生成树(V1与V3)到V2的最短距离更新为了5)
            for (int v = 0; v < n; v++) {
                // 如果v未访问,且u-v有边,且该边比当前记录的距离更小
                if (!visited[v] && graph[u][v] != INF && graph[u][v] < dist[v]) {
                    dist[v] = graph[u][v]; // 更新距离
                }
            }
        }
        return totalWeight;
    }

    public static void main(String[] args) {
        // 定义图的邻接矩阵(6个顶点)
        int[][] graph = {
            // 0  1  2  3    4    5
            {0, 6, 1, 5, INF, INF},    // 顶点0的边
            {6, 0, 5, INF, 3, INF},    // 顶点1的边
            {1, 5, 0, 4, 6, 4},        // 顶点2的边
            {5, INF, 4, 0, INF, 2},    // 顶点3的边
            {INF, 3, 6, INF, 0, 6},    // 顶点4的边
            {INF, INF, 4, 2, 6, 0}     // 顶点5的边
        };
        
        System.out.println("Prim MST Weight: " + prim(graph));
    }
}

模拟流程图




kruskal

加边之前,考虑"加边"的两个端点是不是已经连通,若已连通,则不加("边"为核心,适合稀疏图)

代码

java 复制代码
import java.util.Arrays;
import java.util.Comparator;

public class KruskalMST {
    // 定义边类(起点、终点、权重)
    static class Edge {
        int src, dest, weight;
        public Edge(int src, int dest, int weight) {
            this.src = src;    // 起点
            this.dest = dest;  // 终点
            this.weight = weight; // 边权重
        }
    }

    // 定义并查集的子集类
    static class Subset {
        int parent; // 父节点
        int rank;   // 秩(用于优化)
    }

    // 查找根节点(带路径压缩)
    private static int find(Subset[] subsets, int i) {
        if (subsets[i].parent != i)
            subsets[i].parent = find(subsets, subsets[i].parent); // 路径压缩
        return subsets[i].parent;
    }

    // 合并两个集合(按秩合并)
    private static void union(Subset[] subsets, int x, int y) {
        int xroot = find(subsets, x);
        int yroot = find(subsets, y);
        
        // 将小秩树合并到大秩树下
        if (subsets[xroot].rank < subsets[yroot].rank) {
            subsets[xroot].parent = yroot;
        } else if (subsets[xroot].rank > subsets[yroot].rank) {
            subsets[yroot].parent = xroot;
        } else {
            subsets[yroot].parent = xroot;
            subsets[xroot].rank++; // 秩相同时,合并后秩+1
        }
    }

    public static int kruskal(int[][] graph) {
        int V = graph.length; // 顶点数
        Edge[] edges = new Edge[V*V]; // 边列表(最坏情况下全连接)
        int edgeCount = 0;     // 实际边数计数器
        
        // 将邻接矩阵转换为边列表
        for (int i = 0; i < V; i++) {
            for (int j = i+1; j < V; j++) { // 只遍历上三角避免重复
                if (graph[i][j] != INF) {   // 如果存在边
                    edges[edgeCount++] = new Edge(i, j, graph[i][j]);
                }
            }
        }
        
        // 裁剪边数组到实际大小
        edges = Arrays.copyOf(edges, edgeCount);
        // 按边权重升序排序
        Arrays.sort(edges, Comparator.comparingInt(o -> o.weight));
        
        // 初始化并查集
        Subset[] subsets = new Subset[V];
        for (int v = 0; v < V; v++) {
            subsets[v] = new Subset();
            subsets[v].parent = v; // 初始时每个顶点是自己的父节点
            subsets[v].rank = 0;    // 初始秩为0
        }
        
        int totalWeight = 0;    // MST总权重
        int selectedEdges = 0;   // 已选边数
        int i = 0;              // 当前处理的边索引
        
        // 当已选边数 < V-1 且还有未处理的边时继续
        while (selectedEdges < V - 1 && i < edges.length) {
            Edge nextEdge = edges[i++]; // 取出当前最小权重边
            
            int x = find(subsets, nextEdge.src);  // 查找起点所在集合
            int y = find(subsets, nextEdge.dest); // 查找终点所在集合
            
            // 如果不在同一集合(不会形成环)
            if (x != y) {
                union(subsets, x, y);         // 合并集合
                totalWeight += nextEdge.weight; // 累加权重
                selectedEdges++;              // 已选边数+1
            }
        }
        
        return totalWeight;
    }

    public static void main(String[] args) {
        // 定义与Prim相同的图
        int[][] graph = {
            {0, 6, 1, 5, INF, INF},
            {6, 0, 5, INF, 3, INF},
            {1, 5, 0, 4, 6, 4},
            {5, INF, 4, 0, INF, 2},
            {INF, 3, 6, INF, 0, 6},
            {INF, INF, 4, 2, 6, 0}
        };
        
        System.out.println("Kruskal MST Weight: " + kruskal(graph));
    }
}

代码对应实现案例

左侧为原无向图,右侧为两种最小生成树的求解结果

本文是转载文章,点击查看原文
如有侵权,请联系 xyy@jishuzhan.net 删除
相关推荐
烁34741 分钟前
每日一题(小白)暴力娱乐篇23
java·开发语言·算法·娱乐
俄城杜小帅43 分钟前
数据结构刷题之贪心算法
数据结构·算法·贪心算法
一只码代码的章鱼1 小时前
数据结构与算法-图论-复习1(单源最短路,全源最短路,最小生成树)
c++·算法·图论
什码情况1 小时前
整数编码 - 华为OD统一考试(A卷、C++)
数据结构·c++·算法·华为od
int型码农1 小时前
数据结构第六章(一) -图
c语言·数据结构·算法
Tony沈哲1 小时前
图像编辑器 Monica 之重构滤镜模块、云端部署模型
算法
得物技术1 小时前
DPP推荐引擎架构升级演进之路|得物技术
java·算法·ab测试
Psycho_MrZhang2 小时前
模型量化和剪枝
人工智能·算法·剪枝
梭七y2 小时前
【力扣hot100题】(075)数据流的中位数
算法·leetcode·职场和发展
梭七y2 小时前
【力扣hot100题】(073)数组中的第K个最大元素
算法·leetcode·职场和发展