P3366 【模板】最小生成树 java prim算法 洛谷

本文详细介绍了Prim算法在求解最小生成树问题中的应用,通过链式前向星数据结构,对比了其与Kruskal算法的时间复杂度,并展示了Java代码实例。Prim算法利用节点为中心,逐步扩展生成树,确保每一步都选择与当前树相连的最短边。
摘要由CSDN通过智能技术生成

        传送门:

P3366 【模板】最小生成树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)icon-default.png?t=M85Bhttps://www.luogu.com.cn/problem/P3366        这道题有两种常规做法,kruskal(对边进行研究) 和 prim(对节点进行研究,类似dijikstra)。本文主要讲解prim算法。

        Prim和最短路中的dijkstra很像,由于速度问题,所以这里我用链式前向星存图。Prim的思想是将任意节点作为根,再找出与之相邻的所有边(用一遍循环即可),再将新节点更新并以此节点作为根继续搜,维护一个数组:dis,作用为已用点到未用点的最短距离。

        证明:Prim算法之所以是正确的,主要基于一个判断:对于任意一个顶点v,连接到该顶点的所有边中的一条最短边(v, vj)必然属于最小生成树(即任意一个属于最小生成树的连通子图,从外部连接到该连通子图的所有边中的一条最短边必然属于最小生成树)  

        相比于kruskal算法的O(eloge)复杂度,prim时间复杂度为O(n^{2})。可见,针对不同题目的不同的n和m的取值,我们可以依据实际情况选择kruskal和prim。

         学过dijistra的小伙伴应该一下就能理解下面的代码:

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

class node{
    int pos,dis;
    public node(int pos,int dis){
        this.pos = pos;
        this.dis = dis;
    }
}

public class Main {
    static int N=5001,M=200001;
    static int n,m,cnt,ans,idx;
    static int[] vv = new int[M<<1], to = new int[M<<1];
    static int[] ww = new int[M<<1], he = new int[N];
    static int[] dis = new int[N];
    static boolean[] vis = new boolean[N];
    public static void main(String[] args) throws IOException {
        n=nextInt();
        m=nextInt();
        for(int i=1;i<=m;i++) {
            int u=nextInt(),v=nextInt(),w=nextInt();
            addEdge(u,v,w);
            addEdge(v,u,w);
        }
        prim(1);
        if(idx == n) out.println(ans);
        else out.println("orz");
        out.close();
    }

    public static void prim(int root) {
        PriorityQueue<node> queue = new PriorityQueue<>((o1, o2) -> (o1.dis-o2.dis));
        Arrays.fill(dis, 0x3f3f3f3f);
        dis[root] = 0;
        queue.offer(new node(root,0));
        while(!queue.isEmpty() && idx<n) {
            node tmp = queue.remove();
            int u = tmp.pos;
            int w = tmp.dis;
            if(vis[u]) continue;
            vis[u] = true;
            ans+=w;
            idx++;
            for(int i=he[u];i>0;i=to[i]){
                int v=vv[i];
                if(ww[i] < dis[v]) {
                    dis[v] = ww[i];
                    queue.offer(new node(v, ww[i]));
                }
            }
        }
    }

    public static void addEdge(int u,int v,int w){
        vv[++cnt]=v;
        ww[cnt]=w;
        to[cnt]=he[u];
        he[u]=cnt;
    }

    static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));

    public static int nextInt() throws IOException {
        in.nextToken();
        return (int) in.nval;
    }

    public static String nextString() throws IOException {
        in.nextToken();
        return in.sval;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

玛卡左家陇分卡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值