代码随想录算法训练营第四十九天

卡码网题目:

  • [53. 寻宝(第七期模拟笔试)](#53. 寻宝(第七期模拟笔试))

其他:

今日总结
往期打卡


53. 寻宝(第七期模拟笔试)

跳转:
学习: 代码随想录公开讲解

问题:

在世界的某个区域,有一些分散的神秘岛屿,每个岛屿上都有一种珍稀的资源或者宝藏。国王打算在这些岛屿上建公路,方便运输。

不同岛屿之间,路途距离不同,国王希望你可以规划建公路的方案,如何可以以最短的总公路距离将 所有岛屿联通起来(注意:这是一个无向图)。

给定一张地图,其中包括了所有的岛屿,以及它们之间的距离。以最小化公路建设长度,确保可以链接到所有岛屿。

思路:

Prime算法,找一个起点一层层更新最小值,和Dijkstra类似,更新后是距离树的值,不用加起点到当前.

一共三步操作

扫描一遍找到当前树可到达的最近节点

记录最近节点(加入生成树)

用最近节点更新到达各节点的最近距离.

复杂度:

  • 时间复杂度: O ( n 2 ) O(n^2) O(n2)
  • 空间复杂度: O ( n 2 ) O(n^2) O(n2)

代码(朴素Prime):

java 复制代码
import java.util.*;
class Main{
    private static int[] dist;
    private static int n;
    private static int[][] w;
    private static final int INF = 0x3f3f3f3f;
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        n = scanner.nextInt();
        int m = scanner.nextInt();
        dist = new int[n+1];
        w = new int[n+1][n+1];
        // for(int i = 0;i <= n;i++){
        //     for(int j = 0;j <= n;j++){
        //         w[i][j] = i == j ? 0 : INF;
        //     }
        // }
        for(int i = 0;i <= n;i){
            Arrays.fill(w[i],INF);
        }
        for(int i = 0;i < m;i++){
            int u = scanner.nextInt(),v = scanner.nextInt(),weight = scanner.nextInt();
            w[u][v] = w[v][u] = weight;
        }
        prime();
        int ans = 0;
        for(int i = 2;i <= n;i++){
            ans += dist[i];
        }
        System.out.println(ans);
        scanner.close();
    }
    private static void prime(){
        Arrays.fill(dist,INF);
        boolean[] vis = new boolean[n + 1];
        dist[1] = 0;
        for(int i = 1;i <= n;i++){
            int minIdx = -1;
            for(int j = 1;j <= n;j++){
                if(vis[j]) continue;
                if(minIdx==-1||dist[minIdx]>dist[j]){
                    minIdx = j;
                }
            }
            vis[minIdx] = true;
            for(int j = 1;j <= n;j++){
                if(vis[j]) continue;
                if(dist[j]>w[minIdx][j]){
                    dist[j] = w[minIdx][j];
                }
            }
        }
    }

}

复杂度:

  • 时间复杂度: O ( n 2 ) O(n^2) O(n2)
  • 空间复杂度: O ( n l o g m ) O(nlogm) O(nlogm)

代码(优先队列+链式前向星Prime):

java 复制代码
import java.util.*;
class Main{
    private static int[] dist;
    private static int n;
    private static int idx;
    private static int[] head,e,next,w;
    private static final int INF = 0x3f3f3f3f;
    private static void add(int u, int v, int weight){
        e[idx] = v;
        next[idx] = head[u];
        w[idx] = weight;
        head[u] = idx++;
    }
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        n = scanner.nextInt();
        int m = scanner.nextInt();
        dist = new int[n+1];
        head = new int[n+1];
        Arrays.fill(head,-1);
        e = new int[m*2];
        next = new int[m*2];
        w = new int[m*2];
        for(int i = 0;i < m;i++){
            int u = scanner.nextInt(),v = scanner.nextInt(),weight = scanner.nextInt();
            add(u,v,weight);
            add(v,u,weight);
        }
        prime();
        int ans = 0;
        for(int i = 1;i <= n;i++){
            ans += dist[i];
        }
        System.out.println(ans);
    }
    private static void prime(){
        Arrays.fill(dist,INF);
        boolean[] vis = new boolean[n + 1];
        dist[1] = 0;
        PriorityQueue<int[]> queue = new PriorityQueue<>(Comparator.comparingInt(x->x[1]));
        queue.offer(new int[]{1,0});
        while(!queue.isEmpty()){
            int poll = queue.poll()[0];
            if(vis[poll]) continue;
            vis[poll] = true;
            for(int i = head[poll];i != -1;i = next[i]){
                int j = e[i];
                if(vis[j]||w[i]>=dist[j]) continue;
                dist[j] = w[i];
                queue.add(new int[]{j,dist[j]});
            }
        }

    }

}

思路:

Kruskal,从权最小的边开始连接,只要不构成环就合法.

使用并查集检测环.

复杂度:

  • 时间复杂度: O ( n 2 ) O(n^2) O(n2)
  • 空间复杂度: O ( m l o g m ) O(mlogm) O(mlogm)

代码(Kruskal):

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

class Main{
    static class DisJoint{
        int[] parent;
        DisJoint(int n){
            parent = new int[n + 1];
            for(int i = 1;i <= n;i++){
                parent[i] = i;
            }
        }
        public int find(int x){
            return x==parent[x]?x:(parent[x]=find(parent[x]));
        }
        public boolean isSame(int a,int b){
            return find(a) == find(b);
        }
        public void join(int _a,int _b){
            int a = find(_a);
            int b = find(_b);
            if(a==b) return;
            parent[b] = a;
        }
    }
    static class Edge{
        int s;
        int e;
        int w;
        Edge(int _s,int _e,int _w){
            s = _s;
            e = _e;
            w = _w;
        }
    }
    private static int n;
    private static final List<Edge> edges = new ArrayList<>();
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        n = scanner.nextInt();
        int m = scanner.nextInt();
        for(int i = 0;i < m;i++){
            int u = scanner.nextInt(),v = scanner.nextInt(),w = scanner.nextInt();
            edges.add(new Edge(u,v,w));
        }
        System.out.println(Kruskal());
        scanner.close();
    }

    private static int Kruskal() {
        int ans = 0;
        DisJoint disJoint = new DisJoint(n);
        edges.sort(Comparator.comparing(x->x.w));
        for(Edge i:edges){
            if(disJoint.isSame(i.s,i.e)) continue;
            disJoint.join(i.s,i.e);
            ans += i.w;
        }
        return ans;
    }

}

总结

练习了Prime和Kruskal算法

往期打卡

代码随想录算法训练营第四十八天

代码随想录算法训练营第四十六&四十七天

代码随想录算法训练营第四十五天

代码随想录算法训练营第四十四天

代码随想录算法训练营第四十二&四十三天

代码随想录算法训练营第四十一天

代码随想录算法训练营第四十天

代码随想录算法训练营第三十九天

代码随想录算法训练营第三十八天

代码随想录算法训练营第三十七天

代码随想录算法训练营第三十五&三十六天

代码随想录算法训练营第三十四天

代码随想录算法训练营第三十三天(补)

代码随想录算法训练营第三十二天

代码随想录算法训练营第三十一天

代码随想录算法训练营第三十天(补)

代码随想录算法训练营第二十九天

代码随想录算法训练营第二十八天

代码随想录算法训练营第二十七天(补)

代码随想录算法训练营第二十六天

代码随想录算法训练营第二十五天

代码随想录算法训练营第二十四天

代码随想录算法训练营第二十三天

代码随想录算法训练营周末四

代码随想录算法训练营第二十二天(补)

代码随想录算法训练营第二十一天

代码随想录算法训练营第二十天

代码随想录算法训练营第十九天

代码随想录算法训练营第十八天

代码随想录算法训练营第十七天

代码随想录算法训练营周末三

代码随想录算法训练营第十六天

代码随想录算法训练营第十五天

代码随想录算法训练营第十四天

代码随想录算法训练营第十三天

代码随想录算法训练营第十二天

代码随想录算法训练营第十一天

代码随想录算法训练营周末二

代码随想录算法训练营第十天

代码随想录算法训练营第九天

代码随想录算法训练营第八天

代码随想录算法训练营第七天

代码随想录算法训练营第六天

代码随想录算法训练营第五天

代码随想录算法训练营周末一

代码随想录算法训练营第四天

代码随想录算法训练营第三天

代码随想录算法训练营第二天

代码随想录算法训练营第一天

*[53. 寻宝(第七期模拟笔试)]: KamaCoder

相关推荐
渡众机器人2 分钟前
第八届全球校园人工智能算法精英大赛-算法应用赛-渡众机器人智能体对抗挑战赛规则
人工智能·算法·机器人·自动驾驶·自主导航·对抗赛
郝学胜-神的一滴33 分钟前
完全二叉树与堆底层原理深度剖析 | 手写C++大顶堆实现
java·开发语言·数据结构·c++·python·算法
青山木35 分钟前
Hot 100 --- 缺失的第一个正数
算法·leetcode·哈希算法
农民小飞侠36 分钟前
[leetcode] 165. Compare Version Numbers
java·算法·leetcode
装不满的克莱因瓶1 小时前
掌握语义分割经典模型 FCN——从像素分类到端到端分割的奠基之作
人工智能·python·深度学习·算法·机器学习·分类·数据挖掘
学计算机的计算基1 小时前
链表算法上篇:LeetCode 206/234/141/142/160/21 题解与易错点
java·笔记·算法·链表
大白话_NOI1 小时前
【洛谷 P2678】 [NOIP2015 提高组] 跳石头 超详细题解
c++·算法
xwz小王子1 小时前
ICRA 2026深度观察:全栈闭环成标配,中国具身智能势力显著崛起
大数据·人工智能·算法
孬甭_1 小时前
深入解析归并排序:稳定高效的分治典范
算法·排序算法
DXM05211 小时前
第14期|高阶分割模型:Transformer/SegFormer遥感应用
人工智能·python·神经网络·算法·计算机视觉·cnn·ageo