day55 图论章节刷题Part07([53.寻宝]prim算法、kruskal算法)

前言:使用最小生成树的方法解决将所有节点连接起来所需的最小路径问题。

prim算法

Prim算法是一种贪心算法,从任意一个顶点开始构建最小生成树。每次选择当前已加入生成树的顶点中,距离最近的尚未加入生成树的顶点,直到所有顶点都被加入生成树。

适用场景

  • 稠密图:Prim算法在稠密图(边数接近 n2 )中表现较好,因为它的复杂度为O(n^2),其中 n 为节点数量。
  • 单源最短路径:Prim算法可以从任意一个顶点开始构建最小生成树,适合需要从特定顶点开始的情况。
代码实现

prim三部曲:

第一步,选距离生成树最近节点

第二步,最近节点加入生成树

第三步,更新非生成树节点到生成树的距离(即更新minDist数组)

minDist数组 用来记录 每一个节点距离最小生成树的最近距离。由于题目中说了边的权重最大为10000,这里将边的最大值初始化为10001。

代码如下:

java 复制代码
import java.util.*;
public class Main{
    public static void main (String[] args) {
        Scanner scan=new Scanner(System.in);
        int v=scan.nextInt();
        int e=scan.nextInt();
        int[][] grid=new int[v+1][v+1];
        //初始化距离为1001
        for(int i=0;i<=v;i++){
            Arrays.fill(grid[i],10001);
        }
        //根据输入的边的权值建立地图
        for(int i=0;i<e;i++){
            int s=scan.nextInt();
            int t=scan.nextInt();
            int k=scan.nextInt();
            grid[s][t]=k;
            grid[t][s]=k;
        }
        //初始化最小距离为10001
        int[] minDist=new int[v+1];
        Arrays.fill(minDist,1001);
        //建立数组判断节点是否在树中
        boolean[] isInTree=new boolean[v+1];
        //先选择第一个节点加入树中
        minDist[1]=0;
        //外部循环,遍历每一个节点
        for(int i=1;i<=v;i++){
            int minVal=Integer.MAX_VALUE;
            int cur=-1;
            //找到不在树中且距离最近的节点
            for(int j=1;j<=v;j++){
                if(!isInTree[j] && minDist[j]<minVal){
                    minVal=minDist[j];
                    cur=j;
                }
            }
            //将当前节点加入树中
            isInTree[cur]=true;
            //更新节点到数的距离,主要更新与新加入的节点相连的节点
            for(int j=1;j<=v;j++){
                if(!isInTree[j] && grid[cur][j]<minDist[j]){
                    minDist[j]=grid[cur][j];
                }
            }
        }
        //prim算法的循环结束,计算路径总和
        int result=0;
        for(int i=2;i<=v;i++){
            result+=minDist[i];
        }
        System.out.println(result);
    }
}

注意:外部循环是为了确保每个节点都被遍历到。第一个内部循环是找到距离最小生成树最近的节点;第二个内部循环是更新minDist。

kruskal算法

Kruskal算法也是一种贪心算法,但它是从全局角度出发,先将所有边按权重从小到大排序,然后依次选择不形成环的边加入生成树,直到生成树包含所有顶点。

适用场景

  • 稀疏图:Kruskal算法在稀疏图(边数远小于 n2)中表现较好,因为它的复杂度为 nlogn,其中n 为边的数量。
  • 全局最优:Kruskal算法从全局角度出发,适合需要考虑所有边的情况。

代码实现

在代码中,我们可以使用并查集将两个节点加入同一个集合并判断两个节点是否在同一个集合。

时间复杂度:nlogn (快排) + logn (并查集) ,所以最后依然是 nlogn ,n为边的数量。

代码如下:

java 复制代码
import java.util.*;
//定义边的类
class Edge{
    int l,r,val;
    
    Edge(int l,int r,int val){
        this.l=l;
        this.r=r;
        this.val=val;
    }
}

public class Main{
    //题目中节点最多10000,所以初始化并查集的节点10001
    public static int n=10001;
    public static int[] father=new int[n];
    
    public static void init(){
        for(int i=0;i<n;i++){
            father[i]=i;
        }
    }
    
    public static int find(int u){
        return u==father[u]?u:(father[u]=find(father[u]));
    }
    
    public static void join(int u,int v){
        u=find(u);
        v=find(v);
        if(u==v) return;
        else father[v]=u;
    }
    
    public static void main (String[] args) {
        Scanner scan=new Scanner(System.in);
        int v=scan.nextInt();
        int e=scan.nextInt();
        
        List<Edge> edgeList=new LinkedList<>(); 
        for(int i=0;i<e;i++){
            int l=scan.nextInt();
            int r=scan.nextInt();
            int val=scan.nextInt();
            edgeList.add(new Edge(l,r,val));
        }
        
        //排序
        edgeList.sort(Comparator.comparingInt(edge -> edge.val));
        init();
        int result=0;
        for(Edge edge:edgeList){
            int x=find(edge.l);
            int y=find(edge.r);
            if(x!=y){
                result+=edge.val;
                join(x,y);
            }
        }
        System.out.println(result);
    }
}
相关推荐
Epiphany.556几秒前
dfn序优化树上背包
算法
nvvas4 分钟前
JAVA 关于SpringBoot4新版本阅览
java·spring boot
白宇横流学长5 分钟前
基于SpringBoot实现的大创管理系统
java·spring boot·后端
MicroTech20255 分钟前
微算法科技(NASDAQ MLGO)区块链混合检测模型优化确保全网防御策略一致性
科技·算法·区块链
LYFlied8 分钟前
【每日算法】 LeetCode 394. 字符串解码
前端·数据结构·算法·leetcode·面试·职场和发展
Dylan的码园11 分钟前
栈与stack
java·数据结构·链表
董世昌4111 分钟前
break和continue的区别是什么?
java·jvm·算法
Chase_______14 分钟前
【JAVA基础指南(一)】快速掌握基础语法
java·开发语言
夏鹏今天学习了吗18 分钟前
【LeetCode热题100(75/100)】跳跃游戏 II
算法·leetcode·游戏
陈逸轩*^_^*18 分钟前
微服务常见八股(分布式seat, 网关,服务注册与发现、负载均衡、断路器、API 网关、分布式配置中心)
java·微服务