【详解】最小生成树—无脑版

本文介绍了生成树的概念及其在图论中的应用,并详细讲解了两种构造最小生成树的算法——Prim算法和Kruskal算法,包括算法原理及其实现代码。

生成树

定义:如果连通图G的一个子图是一棵包含G所有顶点的树
则称该子图为G的生成树

生成树是一棵树嘛,所以树上任两点之间有且只有一条通路。
这样就免去了环。

一个图的生成树可能会有很多,生成一棵树很简单
随便找一个顶点暴搜就可以
不同的顶点选择和不同的搜索方式都会导致最后的树不同

最小生成树

定义:连通图G的所有生成树中,边权之和最小的生成树就是图G的最小生成树

构造最小生成树最常用的方法有两种

一是Prim,二是Kruskal,如下

Prim

任意在图G中取一个点P
然后看 【以点P为一个端点的边 】中, 哪一个边权最小,把这个点与P点结合成一个集合

这个集合将会是我们的最小生成树
这时候我们的树里已经有两个点了

接着,我们要找到距离这个集合最近的一个点
也就是把这个集合当做一个整体,这个整体向外放射的所有边中有一个边的边权最小
那条边连接的点就是下一个要“收入囊中”的点

不断地重复这一步骤直到所有点都在集合里
我们的最小生成树就建完了
 
这种算法的时间复杂度为O(n^2)

下附代码(数组模拟邻接表)

void prim(){
int i, j, k;
int goal;
int mn;

memset(intree, 0, sizeof(intree));
memset(distt, INF, sizeof(distt));
distt[1] = 0;

for(i = 1; i <= n; i++){

   //以下为寻找到集合最近的点 
mn = INF;
goal = -1;
for(j = 1; j <= n; j++){
if(intree[j])continue;
if(distt[j] < mn){
mn = distt[j];
goal = j;
}
}
intree[goal] = 1;

//cout << mn << endl;
ans += mn;

if(goal == -1){
printf("orz\n");
return ;
}

//以下循环为点到集合距离的维护 
k = head[goal];
while(k != -1){
if(w[k] < distt[v[k]]){
distt[v[k]] = w[k];
}
k = next[k];
}
}
printf("%d\n", ans);
}


Kruskal

虽然比起这个算法,prim就略显繁琐了,但我还是更喜欢prim~

大致思路就是每次取边权最小的边,这些散的边共端点便合成一个一棵树
合成一棵树的时候会用到并查集了
最后聚合成的大树就是最小生成树

虽然不喜欢,但这个算法也是要写的
因为在图不是联通的, 要建多棵树的时候
kruskal比prim要方便一些(比如2013noip货车运输)

下附代码(洛谷3366板题):

int find(int x){
if(fa[x] == x)
   return x;
else
   return fa[x] = find(fa[x]);
}


bool cmp(node x, node y){
return x.wei < y.wei;
}


void init(){
int i, j;
int x, y, z;
    scanf("%d%d", &n, &m);
for(i = 1; i <= n; i++){
fa[i] = i;
}
    for(i = 1; i <= m; i++){
    scanf("%d%d%d", &x, &y, &z);
    cnt ++;
    edge[cnt].u = x;
edge[cnt].v = y;
edge[cnt].wei = z; 
    }
    sort(edge + 1, edge + 1 + cnt, cmp); 
}


void kruskal(){
int i, j;
int ans = 0;
for(i = 1; i <= m; i++){
if(find(edge[i].u ) != find(edge[i].v )){
fa[find(edge[i].u)] = edge[i].v;
ans += edge[i].wei;
}
}
int temp = find(1);
for(i = 2; i <= n; i++){
if(find(i) != temp){
printf("orz");
return ;
}
}
printf("%d", ans);
}


int main() {
init();
kruskal();
return 0;
}


六自由度机械臂ANN人工神经网络设计:正向逆向运动学求解、正向动力学控制、拉格朗日-欧拉法推导逆向动力学方程(Matlab代码实现)内容概要:本文档围绕六自由度机械臂的ANN人工神经网络设计展开,详细介绍了正向与逆向运动学求解、正向动力学控制以及基于拉格朗日-欧拉法推导逆向动力学方程的理论与Matlab代码实现过程。文档还涵盖了PINN物理信息神经网络在微分方程求解、主动噪声控制、天线分析、电动汽车调度、储能优化等多个工程与科研领域的应用案例,并提供了丰富的Matlab/Simulink仿真资源和技术支持方向,体现了其在多学科交叉仿真与优化中的综合性价值。; 适合人群:具备一定Matlab编程基础,从事机器人控制、自动化、智能制造、电力系统或相关工程领域研究的科研人员、研究生及工程师。; 使用场景及目标:①掌握六自由度机械臂的运动学与动力学建模方法;②学习人工神经网络在复杂非线性系统控制中的应用;③借助Matlab实现动力学方程推导与仿真验证;④拓展至路径规划、优化调度、信号处理等相关课题的研究与复现。; 阅读建议:建议按目录顺序系统学习,重点关注机械臂建模与神经网络控制部分的代码实现,结合提供的网盘资源进行实践操作,并参考文中列举的优化算法与仿真方法拓展自身研究思路。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值