【图】最小生成树kruskal

适合稀疏图,

C语言注释版,复习用

//kruskal
#include<stdio.h>
#include<stdlib.h>

#define DIRECTED 0

typedef sturct
{
  int v;
  int w;
}edge;

typedef struct
{
  edge edges[MAXN][MAXN];
  int degree[MAXN];
  int nvertices;
  int nedges;
}graph;
 

 
int main(void)
{
  graph g;
  int i,j;
  int x,y,weight;
  
  memset(0,g->degree,sizeof(g->degree));
  scanf("%d %d",&g->nvertices,&g->nedges);//点数,边数 
  for(i=1;i<=g->nvertices;i++)
  {
  	scanf("%d %d %d",&x,&y,&weight);
        degree[x]++;
  	edges[x][degree[x]].v=y;
  	edges[x][degree[x]].w=weight;
  	if(!DIRECTED)
  	{
          degree[y]++;
          edges[y][degree[y]].v=x;
  	  edges[y][degree[y]].w=weight;
  	}
  }
  
  

  return 0;  
}
//边的两端点分别保存在数组u和数组v中,权值保存在数组w中 
int Kruskal(){
  for(int i = 1; i <= m; ++i) r[i] = i; //初始化边序号 
  for(int i = 1; i <= n; ++i) p[i] = i;//初始化并查集 
  sort(r+1, r+m+1, cmp);//边排序 
  int k = 0, ans = 0;
  for(int i = 1 ; i <= m; ++i) {
    int e = r[i];//从小到大遍历边 
    int x = find(u[e]), y = find(v[e]);//并查集检验连通分量 
    if(x!=y)//当两者不在同一个连通分量内,将边插入 
	{ 
	  ans += w[e];
	  ++k;//k值应该为在最小生成树内的边数 
	  p[x] = y;//改边,将末端值顺便修改,增加并查集效率 
	}
    if ( k == n-1 )//提前结束 
	  break;
  }  
  int root = find(1);//检验是否有奇葩事件,防止错误 
  for(int i =1 ;i <=n; ++i) if(find(i)!=root) return -1;
  return ans;
}


C++模板
struct KRUSKAL
{
	const int MAXN = 109;
	const int MAXE = 5009;
 
	struct EDGE
	{
		int u, v, length, choose;
	}	edge[ MAXE ];
 
	int path[ MAXN ];
	int N, edgecnt, sum;
 
	void Addedge(int u, int v, int len)
	{
		++edgecnt;
		edge[ edgecnt ].u = u;
		edge[ edgecnt ].v = v;
		edge[ edgecnt ].length = len;
		edge[ edgecnt ].choose = false;
		return ;
	}
 
	void Set()
	{	
		for (int i = 1; i <= N; i++)
			path[i] = i;
		return ;
	}
 
	int Find_Path(int x)
	{
		if (x != path[x]) path[x] = Find_Path( path[x] );
		return path[x];
	}
 
	int Work()
	{
		int cnt = 0, x, y;
		Qsort(1, edgecnt);	// i < j -> edge[i].length < edge[j].length
		Set();
		for (int i = 1; i <= E && cnt < N - 1; i++)
		{
			x = Find_Path( edge[i].u );
			y = Find_Path( edge[i].v );
			if (x == y) continue;
			path[x] = path[y];
			edge[i].choose = true, ++cnt;
			sum += edge[i].length;
		}	
		return sum;
	}
}	Kruskal;

 

邪恶的超简洁代码,背板

#include <iostream>
using namespace std;
const int MAXV = 1024, MAXE = 100001;
int n, m, f[MAXV], ans, cnt;
struct edge{
	int f, t, w;
}es[MAXE];
bool cmp(const edge &a, const edge &b){
	return a.w < b.w;
}
void Fill(int &a){
	static int cnt = 0;
	a = ++cnt;
}
int get(int x){
	return x == f[x] ? x : f[x] = get(f[x]);
}
void Kruskal(const edge &e){
	if(get(e.f) != get(e.t)){
		f[get(e.f)] = get(e.t);
		ans += e.w;
		cnt++;
	}
}
void Read(edge &e){
	cin>>e.f>>e.t>>e.w;
}
int main()
{
	cin>>n>>m;
	for_each(es+1, es+m+1, Read);
	make_heap(es+1, es+m+1, cmp);
	sort_heap(es+1, es+m+1, cmp);
	for_each(f+1, f+n+1, Fill);
	for_each(es+1, es+m+1, Kruskal);
	cout<<(cnt < n-1 ? -1: ans)<<endl;
	return 0;
}


 


                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Kruskal算法是一种用于查找最小生成树的方法。它的基本思想是将中的所有边按照权值从小到大进行排序,然后依次选择权值最小的边,如果这条边的两个顶点不在同一个连通分量中,就将这条边加入最小生成树的边集合中,并将这两个顶点合并到同一个连通分量中。重复这个过程,直到最小生成树的边集合中包含了中的所有顶点,或者边集合中的边数达到了N-1(N为中顶点的个数)。 以下是使用Kruskal算法求最小生成树的步骤: 1. 将中的所有边按照权值从小到大进行排序。 2. 创建一个空的边集合,用于存储最小生成树的边。 3. 创建一个空的连通分量集合,用于存储中的顶点的连通分量。 4. 遍历排序后的边集合,依次选择权值最小的边。 5. 如果这条边的两个顶点不在同一个连通分量中,将这条边加入最小生成树的边集合中,并将这两个顶点合并到同一个连通分量中。 6. 重复步骤4和步骤5,直到最小生成树的边集合中包含了中的所有顶点,或者边集合中的边数达到了N-1。 以下是一个使用Kruskal算法求最小生成树的示例代码: ```python class UnionFind: def __init__(self, n): self.parent = list(range(n)) self.rank = [0] * n def find(self, x): if self.parent[x] != x: self.parent[x] = self.find(self.parent[x]) return self.parent[x] def union(self, x, y): root_x = self.find(x) root_y = self.find(y) if root_x != root_y: if self.rank[root_x] < self.rank[root_y]: self.parent[root_x] = root_y elif self.rank[root_x] > self.rank[root_y]: self.parent[root_y] = root_x else: self.parent[root_y] = root_x self.rank[root_x] += 1 def kruskal(graph): edges = [] for u in range(len(graph)): for v in range(u + 1, len(graph)): if graph[u][v] != 0: edges.append((u, v, graph[u][v])) edges.sort(key=lambda x: x[2]) uf = UnionFind(len(graph)) mst = [] for edge in edges: u, v, weight = edge if uf.find(u) != uf.find(v): uf.union(u, v) mst.append(edge) return mst # 示例的邻接矩阵表示 graph = [ [0, 2, 0, 6, 0], [2, 0, 3, 8, 5], [0, 3, 0, 0, 7], [6, 8, 0, 0, 9], [0, 5, 7, 9, 0] ] mst = kruskal(graph) vertex_set = set() edge_set = set() for edge in mst: u, v, weight = edge vertex_set.add(u) vertex_set.add(v) edge_set.add((u, v)) print("顶点集合:", vertex_set) print("边的集合:", edge_set) ``` 运行以上代码,可以得到最小生成树的顶点集合和边的集合。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值