1,应用场景—修路问题

  • 如图,此时有7个村庄['A', 'B', 'C', 'D', 'E', 'F', 'G'],现在需要把这7个村庄连通
  • 村庄之间的连接线表示可能修路的图示,权值表示举例
  • 此时,如果想要把7个村庄连通,怎么才能让连接的路程最短?
  • 此时应该尽可能的寻找少的线路,保证每条线路最短,最终达到整体线路最短(该部分有点类似贪心,但是贪心的最终结果不一定是最优解)

2,最小生成树问题

  • 修路问题本身就是最小生成树(Minimum Cost Spanning Tree)问题,简称MST:给定一个无向的带权连接图,如果选取一颗生成树,使树上所有边上全的总和最小,就叫最小生成树
  • 树中如果包含N个顶点,则一定包含N-1个边
  • 树中必须包含全部的顶点
  • N-1个边都必须在图的描述中
  • 最小生成树的算法主要是普里姆算法和克鲁斯卡算法
  • 如上图所示,表示一张完全图可能生成的生成树,在包含全部顶点的情况下,边的数量一定是N-1;最终最小生成树,就是所有生成树权值相加最小的一个

3,普里姆算法介绍

  • 普里姆算法求最小生成树,每次从已访问的顶点集合和未访问的顶点集合中选出其中一个已访问顶点和未访问顶点的连接权值中最小的一个,并对连接点和权值进行记录,最终汇总形成最小生成树
  • 普里姆算法具体步骤如下
  1. 构建一个顶点集合,和顶点关联关系的二维数组集合,并假设顶点之间已经全部存在关联关系;没有建立关联关系的用一个最大值表示
  2. 此时从顶点集合中选出任意一个顶点,并将该顶点标记为已读(通过一个外部数组完成)
  3. 将所有已读顶点和未读顶点的关联权值进行比较,注意,此处是用已读顶点和未读顶点比较, 同类不能直接比较,取出权值最小的连接关系
  4. 此时该已读顶点和未读顶点的连接权值构成了当前场景下的最优连接权值(此处类似于贪心算法,每一步都期望最优解,普里姆算法最终结果也是最优解)
  5. 将该未读顶点标记为已读顶点,然后重复第三步动作,直到所有的路径构建完成
  6. 最终需要构建的路径数量 = 顶点数量 - 1条,该部分会在代码第一层循环中体现
  7. 图示:

4,代码实现

package com.self.datastructure.algorithm.prim;import java.util.Arrays;/*** 普里姆算法* * 假设顶点之前已经全部存在关联, 没有关联的用一个最大值表示* * 从任意一个指定顶点开始, 并将该顶点标记为已读* * 将所有已读顶点与所有未读顶点的关联权值进行比较, 取出最小的关联权值* * 此时该已读顶点与该未读顶点构成了当前场景下的最优路径(此处类似于贪心算法, 每一步都要最优解, 都要最小路径)* * 并将该未读顶点标记为已读顶点* * 重复第三步, 直到所有路径都构建完成* * 在N个顶点时, 路径有N-1条* @author PJ_ZHANG* @create 2020-07-09 15:01**/
public class Prim {/*** 表示顶点未连接*/private static final int NOT_CONNECT = Integer.MAX_VALUE;public static void main(String[] args) {// 顶点列表char[] vertexArr = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};// 顶点对应的与各个顶点的连接情况, 此处没有排除顶点自连接// NOT_CONNECT表示没有连接, 且二维顺序与顶点列表顺序一致int[][] vertexMap = {{NOT_CONNECT, 5, 7, NOT_CONNECT, NOT_CONNECT, NOT_CONNECT, 2},{5, NOT_CONNECT, NOT_CONNECT, 9, NOT_CONNECT, NOT_CONNECT, 3},{7, NOT_CONNECT, NOT_CONNECT, NOT_CONNECT, 8, NOT_CONNECT, NOT_CONNECT},{NOT_CONNECT, 9, NOT_CONNECT, NOT_CONNECT, NOT_CONNECT, 4, NOT_CONNECT},{NOT_CONNECT, NOT_CONNECT, 8, NOT_CONNECT, NOT_CONNECT, 5, 4},{NOT_CONNECT, NOT_CONNECT, NOT_CONNECT, 4, 5, NOT_CONNECT, 6},{2, 3, NOT_CONNECT, NOT_CONNECT, 4, 6, NOT_CONNECT}};MyGraph myGraph = new MyGraph(vertexArr.length);myGraph.setVertexArr(vertexArr);myGraph.setVertexMap(vertexMap);// 从0索引开始进行连接prim(myGraph, 1);}private static void prim(MyGraph myGraph, int startIndex) {// 展示二维图myGraph.showVertexMap();// 初始化一个顶点访问情况的数组, 未访问为0, 访问为1int[] visitArr = new int[myGraph.getVertexCount()];// 默认当前节点已经访问visitArr[startIndex] = 1;// 定义最小长度int minValue = NOT_CONNECT;// 定义权值最小时, 已访问的顶点坐标和未访问的顶点坐标int hasVisited = -1;int notVisited = -1;// 顶点有N个, 则顶点间的变肯定存在N-1个, 所以一定存在N-1个边for (int i = 0; i < myGraph.getVertexCount() - 1; i++) {// 下面循环, 从已经被访问的顶点和还没有被访问的顶点中// 寻找出权值最小的路径作为下一步需要连接的路径for (int x = 0; x < myGraph.getVertexCount(); x++) {for (int y = 0; y < myGraph.getVertexCount(); y++) {// x对应值为1表示该顶点已经被访问过// y对应值为0, 表示该顶点还没有被访问过if (visitArr[x] == 1 && visitArr[y] == 0) {// 如果这两个顶点的连接值较小, 则进行记录if (myGraph.getVertexMap()[x][y] < minValue) {minValue = myGraph.getVertexMap()[x][y];hasVisited = x;notVisited = y;}}}}// 一条边处理完成后, 对这条边进行记录if (minValue != NOT_CONNECT) {// 标记未访问的顶点未已访问visitArr[notVisited] = 1;// 表示最小长度为初始长度minValue = NOT_CONNECT;// 打印顶点连接情况System.out.println("顶点 " + myGraph.getVertexArr()[hasVisited] + " 与顶点 "+ myGraph.getVertexArr()[notVisited] + " 连接, 权值为: "+ myGraph.getVertexMap()[hasVisited][notVisited]);}}}/*** 图对象*/static class MyGraph {/*** 顶点*/private char[] vertexArr;/*** 顶点权值图*/private int[][] vertexMap;/*** 顶点数量*/private int vertexCount;public MyGraph(int vertexCount) {this.vertexCount = vertexCount;this.vertexArr = new char[vertexCount];this.vertexMap = new int[vertexCount][vertexCount];}public void showVertexMap() {for (int[] curr : vertexMap) {System.out.println(Arrays.toString(curr));}}public char[] getVertexArr() {return vertexArr;}public void setVertexArr(char[] vertexArr) {if (vertexArr.length > this.vertexArr.length) {throw new IndexOutOfBoundsException("顶点数组越界");}this.vertexArr = vertexArr;}public int[][] getVertexMap() {return vertexMap;}public void setVertexMap(int[][] vertexMap) {if (vertexMap.length > this.vertexMap.length) {throw new IndexOutOfBoundsException("顶点连接线数组越界");}this.vertexMap = vertexMap;}public int getVertexCount() {return vertexCount;}}}

普里姆(Prim)算法(P算法):修路问题相关推荐

  1. 普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法

    图是一种基础又重要的数据结构,图的生成树是图的一个极小连通子图.最小生成树是无向连通网的所有生成树中边的权值之和最小的一棵生成树.求图的最小生成树可以牵引出很多经典的题目,例如在N个城市之间建立通讯网 ...

  2. 【数据结构】克鲁斯卡尔(Kruskal)算法 —PK— 普里姆(Prim)算法

    目录 一.克鲁斯卡尔(Kruskal)算法 二.普里姆(Prim)算法 三.两个算法对比 求图的最小生成树的典型算法: 克鲁斯卡尔(Kruskal)算法 普里姆(Prim)算法 注:考虑问题的出发点相 ...

  3. 数据结构与算法(7-3)最小生成树(普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法)

    目录 一.最小生成树简介 二.普里姆算法(Prim) 1.原理 2.存储 2-1.图顶点和权: 2-3. 最小生成树: 3.Prim()函数 3-1.新顶点入树 3-2.保留最小权 3-3. 找到最小 ...

  4. 最小生成树——普里姆(Prim)算法

    Prim算法的基本思想是以顶点为主导地位:从起始顶点出发,通过选择当前可用的最小权值的边把其他顶点加入到生成树中来.设连通无向网为G(V,E),在普里姆算法中,将顶点集合V分成两个子集T和T'. (1 ...

  5. 一文带你弄懂普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法

    Prim算法 Prim算法用于构造最小生成树,且适用于稠密图. 基本思想 : 归并顶点 设连通网络 N = { V, E } 从某顶点 u0 出发, 选择与它关联的具有最小权值的边(u0, v), 将 ...

  6. 普里姆算法(Prim算法)

    普里姆算法(Prim算法) 简介 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex ...

  7. 最小生成树之普里姆算法

    为了能够讲明白这个算法,我们先构造网图的邻接矩阵,如图7-6-3的右图所示. 也就是说,现在我们已经有了一个存储结构为MGraph的MG(见<邻接矩阵创建图>).MG有9个顶点,它的二维数 ...

  8. 用c语言描述普里姆算法和克鲁斯卡尔算法,克鲁斯卡尔算法+普里姆算法 详解

    克鲁斯卡尔算法: [1]克鲁斯卡尔算法 普里姆算法是以某顶点为起点,逐步找各顶点上最小权值的边来构建最小生成树. 克鲁斯卡尔算法是直接以边为目标去构建. 因为权值是在边上,直接去找最小权值的边来构建生 ...

  9. 数据结构与算法|最小生成树算法(普里姆算法、克鲁斯卡尔算法)

    最小生成树算法 C语言代码部分来自小甲鱼的<数据结构与算法> 文章目录 最小生成树算法 一.普里姆(Prim)算法 1.C语言代码 2.算法思路 二.克鲁斯卡尔(Kruskal)算法 1. ...

  10. 普里姆算法和迪克斯特拉算法

    迪克斯特拉算法         迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959年提出的,因此又叫狄克斯特拉算法.是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短 ...

最新文章

  1. Tensorflow—tensorboard网络结构
  2. python openstack oslo_config使用_OpenStack配置解析库oslo.config的使用方法
  3. :before 和 :after
  4. 《深入理解Android 卷III》第四章 深入理解WindowManagerService
  5. Redis的Linux单机版安装
  6. 聚类算法的java实现_聚类算法之BIRCH(Java实现)
  7. Web前端工作笔记002---json数据查询的方法_json查询大全,JsonSQL数据查询,jfunk数据查询
  8. 爱奇艺、优酷、腾讯独播内容均超70%,如果只能三选一,哪家会员最值得买?
  9. 2021-02-02 天地图图层类型
  10. 揭秘《英雄联盟》的游戏自动化测试
  11. PS、PR素材资源网站
  12. 清华贫困生的树洞,没有卖惨与诉苦,那股韧劲直抵人心
  13. 基于spss的聚类分析(Cluster analysis)
  14. Latex页眉三种形式设置
  15. Unity3D手游-横版ACT游戏完整源代码下载
  16. 【工具】批量修改文件名
  17. 蓝牙的ATT协议(属性协议)和GATT协议
  18. 魔塔小游戏Java版项目完整版
  19. 教你一招:修复win7 系统自带的截图工具损坏
  20. 【iOS】判断硬件型号

热门文章

  1. PHP根据身份证号计算年龄和年龄分段
  2. 功能齐全的涂鸦软件WTest
  3. 谷歌眼镜将要开始限时发售,你准备好了吗?
  4. 设计模式:六大原则之迪米特原则
  5. python文件必须在c盘吗_python必须装在c盘吗
  6. micropython 01stuido canmv 实现2048游戏
  7. 读博士与坐牢的惊人相似
  8. STIL中的Singals
  9. Pytorch定位NaN
  10. 7-23 编程打印空心字符菱形