最小生成树(MST)Prim算法和Kruskal算法
刚学完最小生成树,赶紧写写学习的心得(其实是怕我自己忘了)
最小生成树概念:一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。
就是说如果我们想把一张有n个点的图连接起来,那我们就只需要n-1条边(原因显然:就如同一条有n个点的线段,他们之间最少需要n-1条边连起来)
最小生成树就是寻找值最小的这n-1个点,把他们加和。
首先,最小生成树最基本的算法是Prim和Kruskal算法
Prim算法:
算法分析&思想讲解:
Prim算法采用“蓝白点”思想:白点代表已经进入最小生成树的点,蓝点代表未进入最小生成树的点。
Prim算法每次循环都将一个蓝点u变为白点,并且此蓝点u与白点相连的最小边权min[u]还是当前所有蓝点中最小的。
这样相当于向生成树中添加了n-1次最小的边,最后得到的一定是最小生成树。
Prim算法的好处就在于它与边无关,主要用于稠密图,复杂度为O(n^2),实用度不如Kruskal算法高
代码介绍:(好像不可以直接用,有点问题)
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int MAXN=5010;
int t[MAXN][MAXN];
bool b[MAXN];
int MIN[MAXN];
int main(){
memset(b,false,sizeof(b));
memset(t,127,sizeof(t));
memset(MIN,127,sizeof(MIN)); //把每一条未赋值的边赋为较大的一个数
int n,m;
int ans=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)t[i][i]=0;
for(int i=1;i<=n;i++){ //邻接矩阵存图
for (int j=1;j<=n;j++){ //不同问题存图方式不同
cin>>t[i][j];
}
}
MIN[1]=0;
//先找点:
for(int i=1;i<=n;i++){
int x=0; //x为0 就是说一开始是从一个虚拟点开始的 然后我们找与它相邻的边并且还没被找过的点
for(int j=1;j<=n;j++){
if(!b[j]&&MIN[j]<MIN[x]){ //我们以这一个点开始寻找与它相邻的最小的边
x=j; //然后就标记这个点以便于接着用这个点继续往下找
}
} b[x]=true; //找完这个点后就变成白点,表示已找过
//再扩边:
for(int j=1;j<=n;j++){
if(!b[j]&&MIN[j]>t[x][j]){ //这段代码就是给我们刚找到的X点的邻边赋实际值,这样在下次寻找X的最小边时就可以找到啦
MIN[j]=t[x][j]; //所以说找点的代码就比较好理解了
}
}
}
for(int i=1;i<=n;i++){
ans+=MIN[i];//求最小和
}
cout<<ans<<endl;
return 0;
}
知识扩展:本算法在移动通信、智能交通、移动物流、生产调度等物联网相关领域都有十分现实的意义,采用好的算法,就能节省成本提高效率。
Kruskal算法:
算法分析:
Kruskal算法是将一个连通块当做一个集合。Kruskal首先将所有的边按从小到大顺序排序(一般使用快排),并认为每一个点都是孤立的,分属于n个独立的集合。
然后按顺序枚举每一条边。如果这条边连接着两个不同的集合,那么就把这条边加入最小生成树,这两个不同的集合就合并成了一个集合(这就是一条边);
如果这条边连接的两个点属于同一集合(说明这条边找过了),就跳过。直到选取了n-1条边为止。
思路讲解:
Kruskal算法每次都选择一条最小的,且能合并两个不同集合的边,一张n个点的图总共选取n-1次边。因为每次我们选的都是最小的边,所以最后的生成树一定是最小生成树。每次我们选的边都能够合并两个集合,最后n个点一定会合并成一个集合。通过这样的贪心策略,Kruskal算法就能得到一棵有n-1条边,连接着n个点的最小生成树。
Kruskal算法的时间复杂度为O(E*logE),E为边数。
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN=10010;
int fa[MAXN]; int m,k,ans,x;
struct Edge{
int s,t,w;
}edge[MAXN<<1];
int find(int x){
if(fa[x]==x)return x;
return fa[x]=find(fa[x]);
}
void unionn(int x,int y){
int xx=find(x);
int yy=find(y);
if(xx!=yy){
fa[xx]=yy;
}
}
int cmp(const Edge &a,const Edge &b){
if(a.w<b.w)return 1;
else return 0;
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>x;
if(x!=0){
m++;
edge[m].s=i;
edge[m].t=j;
edge[m].w=x;
}
}
}
for(int i=1;i<=n;i++)fa[i]=i;
sort(edge+1,edge+1+m,cmp);//按照权值大小排序
for(int i=1;i<=m;i++){
if(find(edge[i].s)!=find(edge[i].t)){//查询两条边是否在一个集合里
unionn(edge[i].s,edge[i].t);//因为是按最小值排序,我们所能选择的肯定是最小的
ans+=edge[i].w;//然后加和
k++;//计边的数
}
if(k==n-1)break;//如果搜够了n-1条边就停止
}
cout<<ans<<endl;
return 0;
}
End...
最小生成树(MST)Prim算法和Kruskal算法的更多相关文章
- 最小生成树之Prim算法和Kruskal算法
最小生成树算法 一个连通图可能有多棵生成树,而最小生成树是一副连通加权无向图中一颗权值最小的生成树,它可以根据Prim算法和Kruskal算法得出,这两个算法分别从点和边的角度来解决. Prim算法 ...
- java实现最小生成树的prim算法和kruskal算法
在边赋权图中,权值总和最小的生成树称为最小生成树.构造最小生成树有两种算法,分别是prim算法和kruskal算法.在边赋权图中,如下图所示: 在上述赋权图中,可以看到图的顶点编号和顶点之间邻接边的权 ...
- 【数据结构】最小生成树之prim算法和kruskal算法
在日常生活中解决问题经常需要考虑最优的问题,而最小生成树就是其中的一种.看了很多博客,先总结如下,只需要您20分钟的时间,就能完全理解. 比如:有四个村庄要修四条路,让村子能两两联系起来,这时就有最优 ...
- 最小生成树之 prim算法和kruskal算法(以 hdu 1863为例)
最小生成树的性质 MST性质:设G = (V,E)是连通带权图,U是V的真子集.如果(u,v)∈E,且u∈U,v∈V-U,且在所有这样的边中, (u,v)的权c[u][v]最小,那么一定存在G的一棵最 ...
- 最小生成树(prim算法和kruskal算法)
学习博客:https://www.cnblogs.com/zhangming-blog/p/5414514.html 其实就是加点法:从不属于这个集合的点中找从本集合可以找到的最小边,加入本集合 看代 ...
- 转载:最小生成树-Prim算法和Kruskal算法
本文摘自:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html 最小生成树-Prim算法和Kruskal算法 Prim算 ...
- 最小生成树——Prim算法和Kruskal算法
洛谷P3366 最小生成树板子题 这篇博客介绍两个算法:Prim算法和Kruskal算法,两个算法各有优劣 一般来说当图比较稀疏的时候,Kruskal算法比较快 而当图很密集,Prim算法就大显身手了 ...
- 最小生成树Prim算法和Kruskal算法
Prim算法(使用visited数组实现) Prim算法求最小生成树的时候和边数无关,和顶点树有关,所以适合求解稠密网的最小生成树. Prim算法的步骤包括: 1. 将一个图分为两部分,一部分归为点集 ...
- Prim算法和Kruskal算法
Prim算法和Kruskal算法都能从连通图找出最小生成树.区别在于Prim算法是以某个顶点出发挨个找,而Kruskal是先排序边,每次选出最短距离的边再找. 一.Prim(普里姆算法)算法: ...
- Prim算法和Kruskal算法的正确性证明
今天学习了Prim算法和Kruskal算法,因为书中只给出了算法的实现,而没有给出关于算法正确性的证明,所以尝试着给出了自己的证明.刚才看了一下<算法>一书中的相关章节,使用了切分定理来证 ...
随机推荐
- TR2021_0000偶发数据库连接异常问题排查
[问题描述] 数据库连接异常是很难排查的一类问题.因为它牵涉到应用端,网络层和服务器端.任何一个组件异常,都会导致数据库连接失败.开发遇到数据库连接不上的问题,都会第一时间找DBA来协助查看,DBA除 ...
- laravel5.4 接入qq第三方登录
第一步:先composer安装需要用到的依赖,命令行如下 composer require socialiteproviders/qq 第二步:在config/app.php 中的 providers ...
- go跳出多层循环的几种方式
前言 比如这样的需求, 遍历一个 切片, 切片内容是切片1, 需求是判断切片1中某个是否有相应数据, 有就返回 正文 我们需要考虑的是在写两层遍历时如何在获取结果后结束这两层遍历 变量法 设置一个变量 ...
- ReentrantLock-源码解析
ReentrantLock类注释 1.可重入互斥锁,意思是表示该锁能够支持一个线程对资源的重复加锁,该锁还支持获取锁的公平和非公平性选择.synchronized关键字隐式的支持重进入. 2.可以通过 ...
- python模块详解 | selenium(持续更新中)
目录: 关于selenium Selenium 安装Selenium 安装浏览器驱动 配置环境变量 selenium方法详解 定位元素 元素操作 浏览器操作 鼠标事件 浏览器事件 设置元素等待 多表单 ...
- html2canvas canvas webgl 截图透明空🤣
1. React用这个插件html2canvas完成div截图功能,div里面嵌套canvas,返回base64是透明图片. html2canvas(document.getElementById(& ...
- Memcached Session Manager 共享tomcat session设置
tomcat的lib下添加jar包 修改tomcat的conf目录下的context.xml文件 新增 sessionCookiePath="/" <Manager clas ...
- 【Oracle】sum(..) over(..)用法分析
今天再看sql优化详解的时候,提到了一个sum(..) over(..) 于是自己实验并在网上找了相关的一些文章来看 下面创建一张表: create sequence xulie increment ...
- C# Twain协议调用扫描仪,设置多图像输出模式(Multi image output)
Twain 随着扫描仪.数码相机和其他图像采集设备的引入,用户热切地发现了将图像整合到他们的文档和其他工作中的价值.然而,支持这种光栅数据的显示和操作成本很高,应用程序开发人员需要创建用户界面并内置设 ...
- VS2019中scanf返回值被忽略的问题及其解决方法
目录 [问题](#昨天在使用Visual Studio 2019编写C语言程序时遇到了scanf返回值被忽略问题) 问题原因 方法① 方法② 方法③ 方法④ 昨天在使用Visual Studio 20 ...