贪心算法:最小生成树 Prim算法&Kruskal算法

Prim:
以某个点开始,将最近的相邻点扩充为自己新的集合,再以这个新的集合拉取新的最近点,直到所有点被拉入这个集合,这个集合就是最小生成树。

Kruskal:
“填边”的思想,将边的数据由小到大排序,若新填入的边没有形成环,则这条边就是最小生成树的一部分。判断是否形成环使用并查集的方法。

void Prim(int g[7][7]){	
	int included[7] = {0,1,0,0,0,0,0};//将点1设置为起点 included中在结构体的点会被标记为1	
	int i, j;	
	int sum = 0;	
	for (int roads = 5;roads > 0;roads--)//一共六个点 最小生成树为5条边	
	{		
		int min, mini, minj;		
		min = X;		
		for (i = 1;i < 7;i++)		
		{			
			if (included[i]) //在结构体中的点才会给予搜索			
			{				
				for (j = 1;j < 7;j++)				
				{					
					if (min > g[i][j]&&!(included[i]&&included[j]))					
					{						
						min = g[i][j];						
						mini = i;						
						minj = j;					
					}				
				}			
			}		
		}		
		included[minj] = 1;		
		sum += min;		
		printf("%d->%d %d\n", mini, minj, min);	
	}	
	printf("最小权值和为%d\n", sum);
}
typedef struct {	
	int start;	
	int end;	
	int weight;
}edge;

void edgeSwap(edge *a, edge *b){	
	edge *t=(edge*)malloc(sizeof(edge));	
	t->start = a->start;	
	t->end = a->end;	
	t->weight = a->weight;	
	a->start = b->start;	
	a->end = b->end;	
	a->weight = b->weight;	
	b->start = t->start;	
	b->end = t->end;	
	b->weight = t->weight;	
	free(t);
}

int find(int *pre, int x){	
	int r = x;	
	while (r != pre[r])		
		r = pre[r];	
	return r;
}

void join(int *pre, int x, int y){	
	int GrandX = find(pre, x);	
	int GrandY = find(pre, y);	
	pre[GrandY] = GrandX;
}

void Kruskal(int g[7][7]){	
	edge *a=(edge*)malloc(sizeof(edge)*100);	
	int x = 0;	
	int pre[7] = { 0,1,2,3,4,5,6 };//并查集的准备数组	
	for (int i = 1;i < 6;i++)//抽出边的信息	
	{		
		for (int j = i + 1;j < 7;j++)//无向图,只用对称的一边即可		
		{			
			if (g[i][j] < X)			
			{				
				a[x].start = i;				
				a[x].end = j;				
				a[x].weight = g[i][j];				
				x++;			
			}		
		}	
	} 	
	for (int i = 0;i < x;i++)//将边由小到大排序	
	{		
		for (int j = x - 1;j > i;j--)		
		{			
			if (a[j].weight < a[j - 1].weight)				
				edgeSwap(&a[j], &a[j - 1]);		
		}	
	} 	
	int sum = 0;	
	for (int i = 0;i < x;i++)	
	{		
		if (find(pre,a[i].start)!=find(pre,a[i].end))//判断是否在一个集合内		
		{			
			join(pre, a[i].start, a[i].end);			
			sum += a[i].weight;			
			printf("%d->%d %d\n", a[i].start, a[i].end, a[i].weight);		
		}	
	}	
	printf("最小权值和为%d\n", sum);	
	free(a);
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值