最小生成树

本文深入探讨了无向图中寻找最小生成树的两种经典算法——Prim算法和Kruskal算法。Prim算法通过邻接矩阵实现,逐步构建树直至覆盖所有顶点;而Kruskal算法则通过加边并利用并查集判断环来构造最小生成树。两种算法各有特点,但都能确保权值之和最小,且在某些情况下可能得到不同的树结构。代码示例展示了这两种算法的实现细节。
摘要由CSDN通过智能技术生成

定义

  • 在无向图中 生成一棵树,这棵树涵盖所有顶点,且权值之和最小

性质

  • 边数=n-1
  • 对于给定的图,最小生成树可能不唯一,但是权值之和一定唯一
  • 每一个结点都是平等的(因为来源于图)
  • O(v2),可以用堆优化为O(VlogV+E)

代码

邻接矩阵

#include<algorithm>
using namespace std;
const int max_n = 30;
const int INF=0x3fffffff;
int n,G[max_n][max_n];
bool vis[max_n] = { false };
int d[max_n];//距离集合的最短距离
//prim算法
//邻接矩阵
void prim()
{
	fill(d, d + n, INF);
	//选出
	d[0] = 0;
	for (int j = 0; j < n ;j++)
	{
		int u = -1, min = INF;
		//选出最近的
		for (int i = 0; i < n; i++)
		{
			if (vis[i] == false && d[i] < min)
			{
				min = d[i];
				u = i;
			}
		}
		//加入集合 更新
		if (u == -1)return;
		vis[u] = true;
		for (int i = 0; i < n; i++)
		{
			if (vis[i] == false && G[u][i] != INF && d[i] > G[u][i])
			{
				d[i] = G[u][i];
			}
		}
	}
	
}

邻接表

#include<algorithm>
#include<vector>
using namespace std;
//最小生成树:在无向图中 生成一棵树,这棵树涵盖所有顶点,且权值之和最小
//1.边数=n-1
//2.对于给定的图,最小生成树可能不唯一,但是权值之和一定唯一
//3.每一个结点都是平等的(因为来源于图)
const int max_n = 30;
const int INF=0x3fffffff;
int n;
struct  node
{
	int v;
	int dis;
};
vector<node*>Adj[max_n];
bool vis[max_n] = { false };
int d[max_n];//距离集合的最短距离
//prim算法
//邻接表
void prim()
{
	fill(d, d + n, INF);
	d[0] = 0;
	for (int j = 0; j < n - 1; j++)
	{
		int u = -1, min = INF;
		for (int i = 0; i < n; i++)
		{
			if (vis[i] == false && d[i] < min)
			{
				min = d[i];
				u = i;
			}
		}
		if (u == -1)return;
		vis[u] = true;
		for (int i = 0; i < Adj[u].size(); i++)
		{
			int v = Adj[u][i]->v;
			int dis = Adj[u][i]->dis;
			if (vis[v] == false && d[v] > dis)
			{
				d[v] = dis;
			}
		}
	}
	
}

Kruskal算法

  • 加最小边 然后判断有没有环
  • 使用并查集 没有环:两个端点的根节点不同
#include<algorithm>
using namespace std;
const int max_n = 30;
const int max_e = 40;
int father[max_n];
int e,n;
struct edge
{
	int s;
	int d;
	int dis;
};
edge edges[max_e];
bool cmp(edge e1,edge e2)
{
	return e1.dis < e2.dis;
}
//找到根节点
int findFather(int v)
{
	int x = v;
	while (father[x] != x)
	{
		x = father[x];
	}
	return x;
}
//合并两个集合
bool Union(int x, int y)
{
	int fx = findFather(x), fy = findFather(y);
	if (fx != fy)
	{
		father[fy] = fx;
		return true;
	}
	return false;
}
int kruskal()
{
	sort(edges, edges + e, cmp);
	int ans = 0;//权值之和
	int cnt = 0;//边数
	for (int i = 0; i < n; i++)
	{
		father[i] = i;
	}
	for (int i = 0; i < e; i++)
	{
		if (Union(edges[i].s, edges[i].d))//判断有没有环
		{
			ans += edges[i].dis;//选择这条边
			cnt++;
		}
		if (cnt == n - 1)
		{
			break;
		}
	}
	
	return ans;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值