c++最小生成树代码

  • 边数和顶点个数上限分别为M和N,注意开辟的数组里面有的大小是M,有的大小是N
#define M 200000  //有几个0就是10的几次方
#define N 100000
  • 结构体: 边edge、顶点node(node用于并查集)
  • 全局数组:边集e,大小是边数上限、点集v,大小是顶点数上限
  • 并查集中,顶点的root为true时该顶点是根节点;当顶点是根节点时,parent等于整棵树的元素个数,否则是该顶点的父节点序号值;初始化的点集中,每个顶点都是单独的一个根节点
struct edge
{
	int x, y, w;
	bool operator <(edge e)
	{
		return w < e.w;
	}
};
edge e[M + 5];

struct node
{
	int parent;
	bool root;
	node()
	{
		parent = 1;
		root = true;
	}
};
node v[N + 5];
  • 并查集操作:查找根节点 find 和合并 unite
  • 合并时,要将元素少的树并到元素多的树上,如果是随便合并,则数据多的时候可能会超时
int find(int a)
{
	while(v[a].root != true)
		a = v[a].parent;
	return a;
}

void unite(int a, int b)
{
	if(v[a].parent > v[b].parent)  //将元素少的树并到元素多的树上
	{
		v[b].root = false;
		v[a].parent += v[b].parent;
		v[b].parent = a;
	}
	else
	{
		v[a].root = false;
		v[b].parent += v[a].parent;
		v[a].parent = b;
	}
}
  • 主函数,Kruskal算法
int main()
{
	int n, m;
	sort(e, e + m);
	int cnt = 0;
	for(int i = 0; i < m; ++i)
	{
		int u = find(e[i].x);
		int v = find(e[i].y);
		if(u != v)
		{
			++cnt;
			unite(u, v);
			//选中了e[i]这条边
			
			if(cnt == n - 1) break;
		}
	}
	if(cnt < n - 1) ;   //不连通
	else ;              //连通
	return 0;
}
  • 求从a到b的一条路径,使得路径上最大边的权值最小
    可以进行最小生成树计算,每次加入一条边之后判断ab是否连通 find(a) == find(b)
    如果连通,刚才加的边就是满足条件的边
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是C++实现Prim算法和Kruskal算法求解最小生成树代码: 1. Prim算法 ```c++ #include <iostream> #include <cstring> using namespace std; const int N = 510; int g[N][N]; // 存储图的邻接矩阵 int dist[N]; // 存储当前点到最小生成树的距离 bool st[N]; // 存储当前点是否已经加入最小生成树 int prim(int n) { memset(dist, 0x3f, sizeof dist); // 初始化dist数组为无穷大 int res = 0; // 存储最小生成树的权值和 for (int i = 0; i < n; i ++ ) { int t = -1; // 存储当前距离最小生成树最近的点 for (int j = 1; j <= n; j ++ ) if (!st[j] && (t == -1 || dist[t] > dist[j])) t = j; if (i && dist[t] == 0x3f3f3f3f) return -1; // 无法构成最小生成树 if (i) res += dist[t]; st[t] = true; for (int j = 1; j <= n; j ++ ) dist[j] = min(dist[j], g[t][j]); } return res; } int main() { int n, m; cin >> n >> m; memset(g, 0x3f, sizeof g); // 初始化邻接矩阵为无穷大 while (m -- ) { int a, b, c; cin >> a >> b >> c; g[a][b] = g[b][a] = min(g[a][b], c); // 无向图存储 } int t = prim(n); if (t == -1) puts("impossible"); else cout << t << endl; return 0; } ``` 2. Kruskal算法 ```c++ #include <iostream> #include <algorithm> using namespace std; const int N = 200010; int p[N]; // 并查集数组 struct Edge { int a, b, w; bool operator< (const Edge &W) const { return w < W.w; } }edges[N]; // 存储边的信息 int find(int x) { if (p[x] != x) p[x] = find(p[x]); return p[x]; } int kruskal(int n, int m) { for (int i = 1; i <= n; i ++ ) p[i] = i; // 初始化并查集 sort(edges, edges + m); // 将边按权值从小到大排序 int res = 0, cnt = 0; // res存储最小生成树的权值和,cnt存储当前加入最小生成树的边数 for (int i = 0; i < m; i ++ ) { int a = edges[i].a, b = edges[i].b, w = edges[i].w; a = find(a), b = find(b); if (a != b) // 如果两个点不在同一个连通块中,则将它们合并 { p[a] = b; res += w; cnt ++ ; } } if (cnt < n - 1) return -1; // 无法构成最小生成树 return res; } int main() { int n, m; cin >> n >> m; for (int i = 0; i < m; i ++ ) cin >> edges[i].a >> edges[i].b >> edges[i].w; int t = kruskal(n, m); if (t == -1) puts("impossible"); else cout << t << endl; return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值