最小生成树算法的实现c++

embedded/2024/10/17 21:26:28/

最小生成树算法的实现c++

题目链接:1584. 连接所有点的最小费用 - 力扣(LeetCode)

主要思路:使用krusal算法,将边的权值进行排序(从小到大排序),每次将权值最小且未加入到连通分量中的值给加入其中。主要需要使用并查集,检查是否在同一个连通分量当中。

class Solution {
public:typedef struct edge{int id; //表示这个点int to; //表示要到达的点int weight;//权重bool operator<(edge a) const{return a.weight>weight;}}edge;int calcute(vector<int> point1,vector<int> point2){return abs(point1[0]-point2[0])+abs(point1[1]-point2[1]);}int find(int u,vector<int>& parents){if(parents[u]==u){return u;}else{return find(parents[u],parents);}}int find(int u,vector<int>& parents)  //路径压缩后的{while(u!=parents[u]){parents[u]=parents[parents[u]];u=parents[u];}return u;}/*bool is_same_parent(int u,int v){if(find(u)==find(v)){return true;}return false;}*/int minCostConnectPoints(vector<vector<int>>& points) {int n=points.size();vector<edge> edges;// vector<bool> is_valid(n,false);vector<int> parents(n,0);for(int i=0;i<n;i++){parents[i]=i;}for(int i=0;i<n;i++){for(int j=i+1;j<n;j++){edge temp1;temp1.id=i;temp1.to=j;temp1.weight=calcute(points[i],points[j]);//  edge temp2;//  temp2=temp1;//  temp2.id=temp1.to;//  temp2.to = temp1.id;edges.push_back(temp1);//  edges.push_back(temp2);}}sort(edges.begin(),edges.end());int count=0;int ans=0;// is_valid[edges[0].id]=true;for(int i=0;i<edges.size();i++){int parent1=find(edges[i].id,parents);int parent2=find(edges[i].to,parents);if(parent1!=parent2){parents[parent2]=parent1;cout<<"取边"<<edges[i].id<<"-"<<edges[i].to<<"权重为:"<<edges[i].weight<<endl;ans+=edges[i].weight;count++;}if(count==n){break;}}return ans;/*for(int i=0;i<edges.size();i++){cout<<"本点:"<<edges[i].id<<"要到达的点:"<<edges[i].to<<"权重为:"<<edges[i].weight<<endl;}return 0;*/}
};

使用prime算法做最小生成树

首先要了解什么是链式前向星

前向星是一种特殊的边集数组,我们把边集数组中的每一条边按照起点从小到大排序,如果起点相同就按照终点从小到大排序,

并记录下以某个点为起点的所有边在数组中的起始位置和存储长度,那么前向星就构造好了.

用len[i]来记录所有以i为起点的边在数组中的存储长度.

用head[i]记录以i为边集在数组中的第一个存储位置.
在这里插入图片描述

在这里插入图片描述

image-20240415105500306

用链式前向星可以避开排序,建立边结构体

struct Edge{int next;int to; //edge[i].to表示第i条边的重点,edge[i].next表示与第i条边同起点的下一条边的存储位置int weight;//边的权值
}
另外还有一个数组head[],它是用来表示以i为起点的第一条边存储的位置,实际上你会发现这里的第一条边存储的位置其实在以i为起点的所有边的最后输入的那个编号.
加边函数为void add(int u,int v,int w)
{edge[cnt].w = w;edge[cnt].to = v;edge[cnt].next = head[u];head[u] = cnt++;
}

在这里插入图片描述
在这里插入图片描述

#include <bits/stdc++.h>
#define INF 0x7f7ff
using namespace std;
int k; //默认初始为0
int head[5010];//由于节点最多为5000个,初始化nodes[i]=0,node[i]表示以第i个节点为起始点第一次出现的位置
struct node{int to;int weight;int next;
}edges[400010];//由于是无向图,要开两倍数组
int n,m;
int ans;
bool vis[5010];//代表该节点是否被访问
int dist[5010];//dis[i]表示已经加入到最小生成树的点到没有加入的点的最短距离
void add(int u,int to,int weight) //实际是逆序的,但不影响结果的正确性,在此使用的是链式前向星,不理解链式前向星的去搜一下前向星相关内容
{edges[++k].to= to;edges[k].weight=weight;edges[k].next = head[u];head[u]=k;
}
void prime()
{fill(dist+1,dist+n+1,INF);dist[1]=0;//选择起点为1for(int i=1;i<=n;i++){int u=-1,minn=INF;for(int j=1;j<=n;j++){if(dist[j]<minn&&!vis[j]) //将距离进行更改,且该点要未被访问{u=j;minn=dist[j]; //更新min值}}if(u==-1){ans=-1;return;}vis[u]=true;ans+=dist[u];for(int j=head[u];j;j=edges[j].next){int v=edges[j].to;if(!vis[v]&&dist[v]>edges[j].weight) dist[v]=edges[j].weight;}}
}
int main()
{cin>>n>>m;for(int i=0;i<m;i++) //建立{int from,to,weight;cin>>from>>to>>weight;add(from,to,weight);add(to,from,weight);}prime();if(ans==-1){cout<<"orz"<<endl;}else{cout<<ans<<endl;}//cout<<edges[0].from<<"-"<<edges[0].to<<"-"<<edges[0].weight<<endl;//cout<<edges[1].from<<"-"<<edges[1].to<<"-"<<edges[1].weight<<endl;// 请在此输入您的代码return 0;
}

由于每次枚举dist比较花费时间,因此可以对其进行优化,使用priority_queue来找最短的距离

struct p
{int id,d;bool operator < (const p &a) const{return a.d<d;}
};
void Prime()
{fill(dist+1,dist+1+n,INF);priority_queue<p> q;p now;now.id=1;now.d=dist[1]=0;q.push(now);while(!q.empty()){p now=q.top();q.pop();int u=now.id;if(now.d!=dist[u]) continue;vis[u]=1;ans+=dist[u];tot++;for(int i=head[u];i;i=edge[i].next){int v=edge[i].to;if(!vis[v]&&dist[v]>edge[i].w){dist[v]=edge[i].w;p nxt;nxt.d=dist[v];nxt.id=v;q.push(nxt);}}}if(tot<n) ans=-1;
}
  if(!vis[v]&&dist[v]>edge[i].w){dist[v]=edge[i].w;p nxt;nxt.d=dist[v];nxt.id=v;q.push(nxt);}}
}
if(tot<n) ans=-1;

}



http://www.ppmy.cn/embedded/4058.html

相关文章

【Python基础】线程

文章目录 [toc]线程与进程的区别与联系同步任务示例 并行任务示例线程调度的“随机性” 线程方法thread_object.start()thread_object.join()thread_object.setDaemon()没有设置守护线程的情况设置守护线程的情况 thread_object.current_thread() 目前爬虫的三种实现单线程爬虫…

如何通过drissionpage以及js逆向过字符/滑块/点选/九宫格验证码文章/视频学习案例

目录 零、各种关于drissionpage文章视频案例解决方案合集一、过字符类验证码反爬实战(自动化和逆向两种解法)二、过滑块类验证码反爬实战(自动化和逆向两种解法)三、过点选类验证码反爬实战(自动化和逆向两种解法)四、过九宫格验证码反爬实战(自动化和逆向两种解法)仅供…

SpringBoot 集成 EasyExcel 3.x 优雅实现 Excel 导入导出

介绍 EasyExcel 是一个基于 Java 的、快速、简洁、解决大文件内存溢出的 Excel 处理工具。它能让你在不用考虑性能、内存的等因素的情况下&#xff0c;快速完成 Excel 的读、写等功能。 EasyExcel文档地址&#xff1a;https://easyexcel.opensource.alibaba.com/ 快速开始 …

PySpark预计算ClickHouse Bitmap实践

1. 背景 ClickHouse全称是Click Stream&#xff0c;Data WareHouse&#xff0c;是一款高性能的OLAP数据库&#xff0c;既使用了ROLAP模型&#xff0c;又拥有着比肩MOLAP的性能。我们可以用ClickHouse用来做分析平台快速出数。其中的bitmap结构方便我们对人群进行交并。Bitmap位…

Stable Diffusion 模型分享:MeinaMix(动漫)meinamix_meinaV11

本文收录于《AI绘画从入门到精通》专栏&#xff0c;专栏总目录&#xff1a;点这里&#xff0c;订阅后可阅读专栏内所有文章。 文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八 下载地址 模型介绍 MeinaMix 的目标是&#xff1a;能够在很少的提示下…

vue3使用阿里oss上传资源(上传图片、视频、文件、pdf等等),删除oss资源。获取STS token的接口

vue3使用阿里oss上传资源 全部oss.ts代码如下&#xff1a; import OSS from "ali-oss";// 获取STS token export const getSTSToken async () > {const STS_TOKEN_URL "....."; // 获取STS token的接口&#xff0c;后端提供// fetch方式可按需更换成…

2024 极术通讯-Arm 推出新一代 Ethos-U AI 加速器及全新物联网参考设计平台

导读&#xff1a;极术社区推出极术通讯&#xff0c;引入行业媒体和技术社区、咨询机构优质内容&#xff0c;定期分享产业技术趋势与市场应用热点。 芯方向 Neoverse S3 系统 IP 为打造机密计算和多芯粒基础设施 SoC 夯实根基 Arm Neoverse S3 作为针对基础设施的第三代系统 I…

[蓝桥杯 2018 省 A] 航班时间

题目链接&#xff1a;航班时间 显然&#xff1a;去程时间飞行时间时差&#xff0c;回程时间飞行时间-时差 列方程组可知&#xff1a;飞行时间&#xff08;去程时间回程时间&#xff09;/2 本道题目还有一个难点在于如何读入和输出&#xff1a;可以采用scanf&#xff08;&…