最小生成树的常用算法模板

关于最小生成树的话,其实很早之前就接触了,当时也写了一篇关于最小生成树的文章,但一直没有好好刷题。

接下来几天会持续更新维护KB-最小生成树专题

最小生成树的算法没有其他算法那么复杂,算法思想比较简单,代码也比较容易。

常见的最小生成树算法由Kruskal算法和Prim算法。

1.Kruskal算法 -- 时间复杂度\(O(m * log m)\)

算法思想:

  1. 建立一个并查集,每个点构成一个集合;
  2. 将边进行从小到大进行排序,依次扫描边edge(u,v,w);
  3. 如果u和v 属于同一个集合,那么跳过这轮循环;
  4. 如果不属于同一个集合,则把u、v合并为同一个集合;
  5. 当集合中的顶点数为n或者扫遍所有边edge,则构成最小生成树。
#include 
#include
#include
using namespace std;
const int manx=1e5+5; //对应顶点数目
const int mamx=1e5+5; //对应边的数目
int n,m,u,v,total=1;
struct edge{
    int start,to;
    long long val;
}bian[mamx];
int a[manx];
long long ans;
int find(int x) //并查集
{
    if(a[x]==x) return x;
    else return a[x]=find(a[x]);
}
bool cmp(edge x,edge y)
{
    return x.val

2.Prim算法

Prim算法跟最短路中的Dijkstra 算法思想相近,有兴趣的可以了解一下:
https://www.cnblogs.com/RioTian/p/12597634.html

算法思想:
1.把1作为起点加入最小生成树集合S;
2.在未访问过的集合T中找出一点距离集合S最近的点,并在T中将其剔除,移入S中;
3.重复2步骤,直到所有点加入S。

朴素算法 时间复杂度 \(O(n^2)\)

const int inf=2147483647;
int a[manx][manx], d[manx], n, m, ans;
bool vis[manx];
void prim(){
	for(int i=1;i<=n;i++) d[i]=inf,vis[i]=0,a[i][i]=0; //初始化各数组
	d[1]=0; //1作为起点
	for(int i=1;i

Prim算法使用堆优化可达到与Kruscal一样的复杂度 \(O(m * log m)\)

#include
#include
#include
#include
#include
using namespace std;
const int manx=5e3+5;
const int mamx=1e5+5;
int k,n,m,cnt,sum,a,b,c;
int head[manx],dis[manx],vis[manx];
struct node{
    int v,w,next;
}e[mamx];
typedef pair p;
priority_queue,greater

>q; //堆优化 void add(int u, int v, int w) //链式前向星建图 { e[++k].v=v; e[k].w=w; e[k].next=head[u]; head[u]=k; } int main() { memset(dis,127,sizeof(dis)); memset(head,-1,sizeof(head)); scanf("%d%d",&n,&m); for(R i=1;i<=m;i++) { scanf("%d%d%d",&a,&b,&c); add(a,b,c); //无向图 add(b,a,c); } dis[1]=0; //一般将1作为最小生成树扩展的起点 q.push(make_pair(0,1)); while(!q.empty() && cnt

尽管堆优化,但不如直接使用Kruskal算法更加方便,因此,稀疏图用Kruskal,稠密图用Prim 。

你可能感兴趣的:(最小生成树的常用算法模板)