4.6--贪心--最小生成树(MST)

news/2025/4/2 15:23:53/

一共有两种方法Prim算法和Kruskal算法都可以看作是应用贪心算法设计策略的例子。

Prim算法--选集合S中所有顶点的邻接点 距离最短的那个点(不属于S)加入集合S

Kruskal算法--每次选取最短的且不构成回路的边

它们都利用了下面的最小生成树性质:如果途中具有最小权值的边只有一条,那么这条边包含在任意一个最小生成树中。

设G=(V,E)是连通带权图,U是V的真子集。如果(u,v)属于E,且顶点u属于U,顶点v属于V-U,且在所有这样的边中,(u,v)的权c[u][v]最小,那么一定存在G的一棵最小生成树,它以(u,v)为其中一条边。这个性质有时也称为MST性质。

 

Prim算法--选集合S中所有顶点的邻接点 距离最短的那个点(不属于S)加入集合S

Prim算法的每一步都会为一棵生长中的树添加一条边,该树最开始只有一个顶点,然后会添加V−1个边。每次总是添加生长中的树和树中除该生长的树以外的部分形成的切分的具有最小权值的横切边。

 描述:首先S中只有一个顶点S={1},然后,只要S!=V说明点还没有取完,就贪心选择满足条件的距离S中最小得边(i,j),把不在S集合中的顶点j添加到S集合中,一直循环到S=V结束

 条件是什么?--选集合S中所有顶点的邻接点 距离最短的那个

按Prim算法选取边的过程如下页图所示

 

Kruskal算法--每次选取最短的且不构成回路的边

首先将G的n个顶点看成n个孤立的连通分支。将所有的边按权从小到大排序

然后从第一条边开始,依边权递增的顺序查看每一条边,并按下述方法连接2个不同的连通分支:当查看到第k条边(v,w)时,如果端点v和w分别是当前2个不同的连通分支T1和T2中的顶点时,就用边(v,w)将T1和T2连接成一个连通分支,然后继续查看第k+1条边;如果端点v和w在当前的同一个连通分支中,就直接再查看第k+1条边。

这个过程一直进行到只剩下一个连通分支时为止。 

 

 伪代码

 代码Prim

//最小生成树Prim算法 
/*每次将能到达的最短的边加进去 
closest[j]是j在S中的邻接顶点,
先找出V-S中使c[j][closest[j]](即lowcost[j]) 值最小的顶点j,
然后根据数组closest选取边(j,closest[j]),然后将j添加到S中,
最后对closest和lowcost做修改 
*/
#include<iostream>
#include<fstream>
#include<string.h>
#define INF 0x3f3f3f
using namespace std;ifstream fin("4d6.txt");
int n,m;//n个顶点,m条边
int c[100][100];
int s[1000];//s[i]=1表示顶点i被挑出来了,在生成树里了 
int closest[1000];//closest[j]是j在S中的邻接顶点
int lowcost[1000];//lowcost[j]就是c[j][closest[j]] 
void Prim(){for(int i=2;i<=n;i++){//初始化 lowcost[i]=c[1][i];closest[i]=1;s[i]=0; }s[1]=1; for(int i=1;i<n;i++){int t=INF;int j=1;//从第一个结点开始 for(int k=2;k<=n;k++){if(lowcost[k]<t && !s[k]){t = lowcost[k]; j=k;}}cout<<"("<<closest[j]<<","<<j<<")= "<<lowcost[j]<<endl;s[j]=1;for(int k=2;k<=n;k++){if(c[j][k]<lowcost[k] && !s[k]){lowcost[k] = c[j][k];closest[k]=j;		}}}
}
int main(){//cin>>n>>m;fin>>n >> m;int i,j;int x,y,z;for(i=0;i<=n;i++) //初始化 for(j=0;j<=n;j++)c[i][j]=INF;for(i=0;i<m;i++){fin>>x>>y>>z;c[x][y]=z;c[y][x]=z;} cout<<"Prim:依次加入的顺序为:\n";	Prim();return 0;
}

 代码kruskal

//最小生成树Kruskal
//每次选图中权值最小的边 
#include<iostream>
#include<string.h>
#include<fstream>
#include<algorithm>
using namespace std;
ifstream fin("4d6.txt");
int n,m;//n个顶点,m条边
int s[1000];//并查集s[i]=1表示顶点i的父结点是1,即i与1在一个集合
struct edge{int u,v,w;//顶点u到顶点v的权重是w(无向图) 
}g[1000];
bool comp(edge a,edge b){return a.w < b.w;
}
void Init(){for(int i=0;i<m;i++){s[i]=i;//初始化,现在各自为王,自己就是一个集合}
} 
int Find(int x){//查询根结点if(s[x]==x)return x;else{s[x]=Find(s[x]);  //顺便把双亲结点也设置为根结点,路径压缩return s[x];}	
}
void Merge(int x,int y){//合并,把 y 合并到 x 中去,就是把y的双亲结点设为xs[Find(y)] = Find(x);
}
void Kruskal(){int x,y;for(int i=0;i<m;i++){x = g[i].u;y = g[i].v;if(Find(x) != Find(y)){cout<<"("<<x<<","<<y<<")= "<<g[i].w<<endl;Merge(x,y);}}
}
int main(){fin>>n>>m;int i;int x,y,z;for(i=0;i<m;i++){fin>>x>>y>>z;g[i].u=x;g[i].v=y;g[i].w=z;} sort(g,g+m,comp);Init();cout<<"依次加入的顺序为:\n";Kruskal();return 0;
}

测试样例

 6  10
1 2 6
1 3 1
1 4 5
2 3 5
2 5 3
3 4 5
3 5 6
3 6 4
4 6 2
5 6 6


http://www.ppmy.cn/news/22012.html

相关文章

SpringCloud系列(九)[docker 篇] - Centos 7 下 Docker 的安装及基本操作指令

本篇文章将详细介绍 Centos 7 下 Docker 的安装以及一些基本操作指令. DockerDocker 的安装步骤Docker 基本操作指令Docker 的安装步骤 步骤一: 确保自己电脑的虚拟机联网并安装了 yum 工具, 如果没有安装 yum, 则执行下面的命令; yum install -y yum-utils \device-mapper-p…

在Ubuntu系统上Qt安装和配置

一、说明 QT界面本不应该做为一个很高的知识点&#xff0c;问题是&#xff0c;在ROS2的程序实验&#xff0c;需要界面支持&#xff0c;或用界面显得更加方便&#xff0c;因而专门启动该栏目专门介绍QT方法。因为体系比较庞大&#xff0c;因此&#xff0c;需要一点一点渗透学习。…

OAuth2入门

1.下载资源 演示代码&#xff1a; OAuth2-example: 演示OAuth2的认证流程https://gitee.com/lisenaq/oauth2-example克隆下载到本地&#xff1a; 导入项目&#xff1a; client 客户 authorization-server 认证服务 resource-owner 资源所有者 resource-server 资源…

【MyBatis】框架特点,ORM思想,事务管理机制

1. Mybatis概述:1.1 基础知识:SSM三大框架: Spring SpringMVC MyBatis框架其实就是对通用代码的封装, 提前写好一堆接口和类, 在做项目的时候直接引入这些常用的借口和类(引入框架), 基于这些现有的接口和类进行开发, 可以大大提高开发效率.框架一般是以jar包的形式存在的, j…

【栈】单调栈详情介绍及其运用

单调栈单调栈的概述&#xff08;Overview&#xff09;何时使用单调栈模拟单调递增栈单调栈的运用&#xff08;算法练习题&#xff09;模板【练习一、单调栈】739. 每日温度【练习二、单调栈哈希表】496. 下一个更大元素 I【练习三、单调栈循环数组】503. 下一个更大元素 II【练…

基本放大器电路- (一)

运算放大器组成的电路五花八门&#xff0c;令人眼花瞭乱&#xff0c;是模拟电路中学习的重点。在分析它的工作原理时倘没有抓住核心&#xff0c;往往令人头大。为此本人特搜罗天下运放电路之应用&#xff0c;来个“庖丁解牛”&#xff0c;希望各位从事电路板维修的同行&#xf…

记录1-两数之和

给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能重复出现。你可以按任意顺序返回答案…

关于图片上传和在页面显示问题

最近在工作中遇到一个关于图片上传的问题。根据之前项目的经验&#xff0c;我知道目前这个公司上传图片有两种方式&#xff0c; 一种是把图片上传到公司服务器上&#xff0c;然后把图片放在服务器上的地址存在数据库中&#xff0c;要获得图片的时候直接从库中拿地址就行了另一…