IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 算法学习:最小生成树 -> 正文阅读

[数据结构与算法]算法学习:最小生成树

最小生成树是无向图中的一个问题,很常见。
在无向图中,连通而且不含有圈(环路)的图称为树。最小生成树(MST)的基本模型可以用下面的题目描述:

题目描述
某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。

输入
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。
当N为0时,输入结束,该用例不被处理。

输出
对每个测试用例,在1行里输出最小的公路总长度。

样例输入
8
1 2 42
1 3 68
1 4 35
1 5 1
1 6 70
1 7 25
1 8 79
2 3 59
2 4 63
2 5 65
2 6 6
2 7 46
2 8 82
3 4 28
3 5 62
3 6 92
3 7 96
3 8 43
4 5 28
4 6 37
4 7 92
4 8 5
5 6 3
5 7 54
5 8 93
6 7 83
6 8 22
7 8 17
0
样例输出
82

图的两个基本元素是点和边,与此对应,有两种方法可以构造最小生成树T。这两种算法都基于贪心法,因为MST问题满足贪心法的“最优性原理”,即全局最优包含局部最优。prim算法的原理是“最近的邻居一定在MST上”,kruskal算法的原理是“最短的边一定在MST上”。
(1)prim算法:对点进行贪心操作。从任意一个点u开始,把距离它最近的点v加入到T中;下一步,把距离{u,v}最近的点w加入到T中,继续这个过程,直到所有点都在T中。
(2)kruskal算法:对边进行贪心操作。从最短的边开始,把它加入到T中;在剩下的边中找最短的边,加入到T中;继续这个过程,直到所有点都在T中。
在这两个算法中,重要的问题是判断圈。最小生成树显然不应该有圈,否则就不是“最小”了。所以,在新加入一个点或者边的时候要同时判断是否形成了圈。

1、prim算法
设最小生成树的点的集合是U,开始时最小生成树为空,所以U为空。
在这里插入图片描述
(1)任取一点,例如点1,放到U中,U={1}。
(2)找离集合U中的点最近的邻居,即1的邻居,是2,放到U中,U={1,2}。
(3)找离U最近的点,是5,U={1,2,5}。
(4)距离U最近的点是5,但是它没有扩展新的点,不符合要求。
(5)加入4,U={1,2,5,4}。
(6)加入3,U={1,2,5,4,3}。所有的点都在U中,结束。
上面的步骤和Dijkstra算法的步骤非常相似,不同的是Dijkstra需要更新U的所有邻居到起点的距离,即“松弛”,而prim则不需要。所以,只需要把Dijkstra的程序简化一些即可。
和Dijkstra算法一样,prim程序也可以用优先队列来查找距离U最近的点,能优化算法。
prim的编程比较麻烦,kruskal更简单且高效。

2、kruskal算法
kruskal算法编程有以下两个关键技术:
(1)对边进行排序。可以用STL的sort()函数,排序后,依次把最短的边加入到T中。
(2)判断圈,即处理连通性问题。这个问题用并查集简单而高效,并查集是kruskal算法的绝配。
任意上面的图为例说明kruskal算法的操作步骤

在这里插入图片描述

(1)初始时最小生成树为空。令S是以节点i为元素的并查集,在开始时,每个点属于独立的集(为了便于讲解,下表中区分了结点i和集S,把集的编号加上可下划线):
在这里插入图片描述
(2)加入第一个短边(1-2):T={1-2}。在并查集S中,把结点2合并到结点1,也就是把结点2的集2改成结点1的集1。
在这里插入图片描述
(3)加入第二个短边(3-4),T={1-2,3-4}。在并查集S中,结点4合并到结点3.
在这里插入图片描述
(4)加入第三个最短边(2-5):T={1-2,3-4,2-5}。在并查集S中,把结点5合并到结点2,也就是把结点5的集5改成结点2的集1.在集1中,所有结点都指向了根结点,这样可以避免并查集的长链问题。
在这里插入图片描述
(5)第四个最短边(1-5)。检查并查集S,发现5已经属于集1,丢弃这个边。这一步实际上是发现了一个圈。并查集的作用就体现在这里。
(6)加入第五个最短边(2-4)。在并查集S中,把结点4的集并到结点2的集。注意这里结点4的集原本为3,实际上的修改是把结点3的集3改成1。
(7)重复以上操作,直到结束。

代码如下:

#include<bits/stdc++.h>
using namespace std;
const int NUM=105;
int S[NUM];//并查集
struct Edge{int u,v,w;}edge[NUM*NUM];
bool cmp(Edge a,Edge b){return a.w<b.w;};
int find(int u){return S[u]==u?u:find(S[u]);}
int n,m;
int kruskal(){
    int ans=0;
    for(int i=1;i<=n;++i)S[i]=i;
    sort(edge+1,edge+m+1,cmp);
    for(int i=1;i<=m;++i){
        int b=find(edge[i].u);
        int c=find(edge[i].v);
        if(b==c)continue;//产生了圈,丢弃这个边
        S[c]=b;//合并
        ans+=edge[i].w;//计算MST
    }
    return ans;
}
int main(){
    while(~scanf("%d",&n)){
        if(!n)return 0;
        m=n*(n-1)/2;
        for(int i=1;i<=m;++i)
            scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
        printf("%d\n",kruskal());
    }
}

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-02-24 15:33:08  更:2022-02-24 15:33:40 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 15:45:22-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码