zoukankan      html  css  js  c++  java
  • 最小生成树(Kruskal克鲁斯卡尔算法)

    最小生成树(克鲁斯卡尔算法)


    如果想看普利姆算法,请移步
    -------->Prime普利姆算法<--------

    接下来是介绍最小生成树的内容。

    什么是最小生成树?

    定义: 各边的代价之和最小的那棵生成树称为该连通网的最小代价生成树( Minimum Cost Spanning Tree ),简称最小生成树。

    构成最小生成树的算法有很多,其中多数的算法都是利用了最下生成树的一种性质:

    性质: 假设N=(V,E)是一个连通网,U是顶点集V的一个非空子集。若(u,v)是一条具有最小权值(或者说代价)的边,其中u∈U,v∈V-U,那么必定存在一颗包含边(u,v)的最小生成树

    总结起来,得具备这些条件:

    • 是一个连通网(连通图)
    • 各边有权值

    如果还不了解,那么我们来举一个例子:

    比方说我们需要在n个城市中建立一个联系网,因为城市众多,我们当然不可能一一给他们都连通,考虑到价格问题,我们必须得用最小的代价从而连通所有的城市。

    该怎么做呢?好难(っ °Д °;)っ


    我们用圆圈来表示每个城市

    all

    然后用箭头中包含的值来表示权值

    part1

    我们的问题来了,我们该怎样去选择,从而达到我们的目的呢? ( 我们的目的是:德玛西亚d=====( ̄▽ ̄*)b.......当然....目的是选择几条路线,组成的权值最小,并且能够把这几个点连接上...... )

    首先我们用眼睛观察.....然后我们很容易选出这几条路线:

    part2

    然后我们来算算,总权值是:1+2+4+5+12=24。没错,这就是最小生成树的构成,我们所选的路线并没有错。那么问题来了。我们是 怎么选 的呢?

    还记得我们刚刚选的方式么?我的思路是,先把他们的各个边按照权值从小到大排序,排完序之后,再从中选出我所需要的边,直到所有的点覆盖完成,当然,如果有一条边是存在于已经连过的两个顶点之间,我就不要了,因为这两个城市已经走过了(●ˇ∀ˇ●)。

    当所有的顶点都连接完成之后,我们的最小生成树也就构成了。如果排完序那么我们是这样的一个序列:

    城市 可通城市 权值
    A B 1
    A D 2
    B F 4
    A E 5
    E F 9
    A C 12
    B C 13
    C D 18
    D E 32

    然后对应 A B C D E F 转换为数字便是: 1 2 3 4 5 6

    然后,我们从小到大,选择便是以下的情况:
    choose1
    choose2
    choose3
    choose4
    choose5

    由于我们有六个点,那么我们选择五条边,就完成了我们所需要的最小生成树。没错,这便是我要说的最小生成树的一种算法:(Kruskal 克鲁斯卡尔算法)

    比较官方的构造过程便是:

    • 假设连通网N=(V,E),将N中的边按权值从小到大的顺序排列
    • 初始状态为只有n个顶点而无边的非连通图T=(V,{}),图中每个顶点自成一个连通分量。
    • 在E中选择权值最小的边,若该边依附的顶点落在T中不同的连通分量上(即不形成回路),则将此边加入到T中,否则舍去此边而选择下一条权值最小的边
    • 重复操作,直到T中所有顶点都在同一连通分量上为止

    一波官方的解释,看着我有点懵 (@_@) ,但是没事,我有自己的理解。接下来便是代码实现了......


    main.cpp

    #include"GraphKruskal.h"
    
    int main()
    {
    	GraphKurskal g1;
    	g1.Init();
    	g1.Kruskal();
    	g1.Display();
    	return 0;
    }
    
    /*
    输入样例:
    1 1 1
    1 4 2
    2 6 4
    1 5 5
    5 6 9
    1 3 12
    2 3 13
    3 4 18
    4 5 32
    
    */
    
    

    GraphKruskal.h

    #pragma once
    #ifndef _GRAPHKRUSKAL_H_
    #define _GRAPHKRUSKAL_H_
    #include<iostream>
    #include<algorithm>
    #include<cstdlib>
    #include<vector>
    using namespace std;
    //	这是利用邻接矩阵来实现的克鲁斯卡尔搜索最小生成树的算法
    struct node
    {
    	int from, to;
    	int sideID;//记录边号,已选定可以输出的边
    	int distance;
    };
    
    class GraphKurskal
    {
    private:
    	vector<node>graph;//记录边
    	vector<bool>visited;//是否经历过
    	vector<int>IDofSide;//每条边的ID
    	int minDistacne;//最小权值
    	int nodeNumber;//几个点
    
    	//void Sort();//这个程序是调用库函数的sort函数进行排序,因此没有写自定义sort函数
    public:
    	void Init();//初始化
    	void Kruskal();//进行克鲁斯卡尔算法,找到最小生成树
    	void Display();//显示
    
    };
    bool cmp(node a1,node a2);//从小到大排序的函数
    
    #endif // !_GRAPHKRUSKAL_H_
    
    

    GraphKruskal.cpp

    #include "GraphKruskal.h"
    
    
    void GraphKurskal::Init()
    {
    	node n1;
    	int i = 0;
    	cout << "请输入有几个点" << endl;
    	cin >> nodeNumber;
    	visited.resize(nodeNumber + 1, false);
    	cout << "请输入各边的关系,'#'结束" << endl;
    	cout << "请按照格式:开始点---终止点---距离" << endl;
    	while ((cin >> n1.from&& n1.from != '#') && (cin >> n1.to&& n1.to != '#'))
    	{
    		cin >> n1.distance;
    		n1.sideID = ++i;
    		graph.push_back(n1);
    	}
    }
    
    void GraphKurskal::Kruskal()
    {
    
    	sort(graph.begin(), graph.end(),cmp);//进行函数比较
    		//当选择的边数不为节点数减一的情况,我们继续循环
    	minDistacne = 0;
    	for (int i = 0; i < graph.size(); i++)
    	{
    		//判断图中的点是否遍历过,如果遍历过,那么跳过,否则继续遍历
    		if (!visited[graph[i].from] || !visited[graph[i].to])
    		{
    			visited[graph[i].from] = true;
    			visited[graph[i].to] = true;
    			IDofSide.push_back(graph[i].sideID);
    			minDistacne += graph[i].distance;
    			if (IDofSide.size() == nodeNumber - 1)
    				break;
    		}
    	}
    }
    
    void GraphKurskal::Display()
    {
    	cout << "总距离是:" << minDistacne << endl<<"权边是:";
    	for (int i = 0; i < IDofSide.size(); i++)
    		cout << graph[IDofSide[i]-1].distance << " ";
    	cout << endl;
    }
    
    bool cmp(node a1, node a2)
    {
    	return a1.distance > a2.distance ? false : true;
    }
    
    

    代码实现结果:
    show1


    借鉴《数据结构C语言版|第2版》


    这是小睿的博客,如果需要转载,请标注出处啦~ヾ(≧▽≦*)o谢谢。
  • 相关阅读:
    openstack 相关服务常用命令整理
    openstack(Pike 版)集群部署(六)--- Horizon 部署
    node express4.x 的安装
    jquery mobile 笔记
    multi-node和generic-pool两大利器
    ADT eclipse的几个快捷键
    安卓入门笔记
    HTML颜色代码表
    [转载]Delphi常用类型及定义单元
    简化连接Buffer对象的过程
  • 原文地址:https://www.cnblogs.com/Yunrui-blogs/p/11884247.html
Copyright © 2011-2022 走看看