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)
    如果连通,刚才加的边就是满足条件的边

你可能感兴趣的:(oj)