Prim 普利姆算法

Stella981
• 阅读 597

最小生成树之普利姆( Prim )算法

如果想看克鲁斯卡尔算法(Kruskal),请移步

--------->这是链接🔗{{>_<}}<-----------


    • 例子
    • 图示
    • 代码

我们来讲述普利姆( Prim )算法。

和克鲁斯卡尔算法一样,普利姆算法也是一种构造最小生成树的算法。

  • 主要思想是:
  • 首先随意从一个点出发,然后每次找他们的最小相邻边,每经过一个顶点,那边找其顶点的最小权值的边。一直到找到了 n 条边,( n=定点数-1 ) 然后我们的算法结束

普利姆算法是利用了贪心思想的特性,但是对于有负权值的边,普利姆算法并不适用,此时应该用克鲁斯卡尔算法 ------>这是我的另一篇文章,讲述克鲁斯卡尔算法,有兴趣看看啊♪(´▽`)<------


举个栗子 (╹ڡ╹ ) :比如有六个城市,分别是城市1,城市2,城市3,城市4,城市5,城市6,我们的目标是:选择几条线路,把这几个城市连起来,让城市间能够相互到达,但是不能有回路。如图.....

Prim 普利姆算法

在这几个城市中,我们测量了每个城市之间的路线,他们的权值分别如下:

开始城市

到达城市

路线长度(权值)

城市1

城市2

1

城市1

城市3

12

城市1

城市4

2

城市1

城市5

5

城市2

城市6

4

城市2

城市4

12

城市6

城市5

4

城市5

城市4

5

城市4

城市3

20

也就是如图所示:

Prim 普利姆算法

然后,我们的目标是,从这几条边中找到能够连通所有点的边并且这些边是最小权值的。也就是像下面的图一样

Prim 普利姆算法

然后我们,从城市1开始吧 o( *  ̄ ▽  ̄ * )o。

从城市1开始的话,我们会把城市1所相邻的边放进一个集合里面,然后找城市1相邻的边的最小值。我们很容易可以找到,它是1,那么我们把1选上,然后1所相连的是城市2,这样,我们找到了第一条路径,并且这条路径是能够从城市1到达城市2的 (o゜▽゜)o☆

Prim 普利姆算法

从城市1开始,我们把边1,2,5,12放进集合了,然后我们选了1,现在把1从集合里面移除。由于加入了城市2,那么我们把城市2相关邻的边放进集合里面,此时集合里面就有了2,5,12,4,12,然后我们再在这里面找权值最小的边,然后再相连,然后重复这个操作。

当你找到一条边,这条边刚刚好两边都经历过了,那我们就舍弃这条边,然后继续向下找,直到所有的点都遍历过了之后,就结束操作,我们就构成了一棵最小生成树。

Prim 普利姆算法

Prim 普利姆算法

Prim 普利姆算法

Prim 普利姆算法


- \[返回\](#back)

然后让我们来看看代码的实现。代码实现,我采用了邻接矩阵的存储结构

main.cpp

#include"GraphPrim.h"

int main()
{
    GraphPrim g1;
    g1.Init();
    g1.Display();
    return 0;
}

GraphPrim.h

#pragma once
#ifndef _GRAPHPRIM_H_
#define _GRAPHPRIM_H_
#include<iostream>
#include<cstdlib>
#include<vector>
using namespace std;

const int MAX = INT_MAX;

class GraphPrim
{
private:
    vector<vector<int>>graph;//邻接矩阵存储点与边的关系
    vector<bool>visited;//判断是否经历过
    vector<int>side;

    vector<int>node;//取点的路径,用来存放输出点的顺序
    vector<int>useSide;//使用的边,用来存放边的权值

    int nodeNumber;//点的个数
    int startPoint;//开始点
    int sum;

    int findMin(vector<int>& ans);//返回下标

public:
    void Init();//初始化
    void Prim(int start);//普利姆算法,以及开始点
    void Display();//显示参数
};


#endif // !_GRAPHPRIM_H_

Graphprim.cpp

#include "GraphPrim.h"

int GraphPrim::findMin(vector<int>& ans)
{
    int index = 0;
    int min = ans[0];
    for (int i = 0; i < ans.size(); i++)
    {
        if (min > ans[i])
        {
            min = ans[i];
            index = i;
        }
    }
    return index;
}

void GraphPrim::Init()
{
    cout << "请输入点的个数" << endl;
    cin >> nodeNumber;

    visited.resize(nodeNumber + 1);//初始化

    graph.resize(nodeNumber + 1);//初始化
    for (int i = 0; i <nodeNumber + 1; i++)
        graph[i].resize(nodeNumber + 1, MAX);

    cout << "请输入开始点" << endl;
    cin >> startPoint;
    int a, b;
    cout << "请输入出发点、到达点和路径长度,以‘#’为全部结束" << endl;
    while ((cin >> a && a != '#') && (cin >> b && b != '#'))
    {
        cin >> graph[a][b];//输入权值
        graph[b][a] = graph[a][b];
    }
}

void GraphPrim::Prim(int start)
{
    int temp;
    sum = 0;        
    side.resize(nodeNumber + 1);
    node.push_back(start);
    visited[start] = true;
    for(int i = 1; i <= nodeNumber; i++)
        side[i] = graph[start][i];    
    for(int i = 1; i <= nodeNumber; i++)//找生成树集合点集相连最小权值的边    
    {
        temp = MAX;
        for(int j = 1; j <= nodeNumber; j++)
            if (!visited[j] && temp > side[j])
            {
                temp = side[start = j];
            }
        if(temp == MAX)//如果是无穷了
            break;    
        visited[start] = true; //加入最小生成树集合
        node.push_back(start);
        useSide.push_back(temp);
        sum += temp;//记录权值之和        
        for(int j = 1; j <= nodeNumber; ++j) //更新边数组    
            if (!visited[j] && side[j] > graph[start][j])
            {
                side[j] = graph[start][j];
            }
    }
}

void GraphPrim::Display()
{
    Prim(startPoint);
    cout << "显示最大权值" << sum << endl;
    cout << "路径显示: ";
    for (int i = 0; i < node.size(); i++)
        cout << node[i] << " ";
    cout << endl;
}
  • 返回
点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Easter79 Easter79
3年前
swap空间的增减方法
(1)增大swap空间去激活swap交换区:swapoff v /dev/vg00/lvswap扩展交换lv:lvextend L 10G /dev/vg00/lvswap重新生成swap交换区:mkswap /dev/vg00/lvswap激活新生成的交换区:swapon v /dev/vg00/lvswap
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这