C语言求最小生成树 普利姆算法(贪心思想)

目的:

1.掌握能用贪心法求解的问题应满足的条件;

2.加深对贪心法算法设计方法的理解与应用;

3.锻炼对程序跟踪调试能力;

4.练习培养应用所学知识解决实际问题的能力。

问题描述:

设G =(V,E)是无向连通带权图,即一个网络。(V是顶点集合,E是边集合)如果G的子图G’是一棵包含G的所有顶点的树,则称G’为G的生成树。生成树上各边权的总和称为该生成树的耗费。在G的所有生成树中,耗费最小的生成树称为G的最小生成树。

贪心选择策略: 每次都选择到下一顶点权最小的边。

基本步骤:

1.置顶点集合S={1};

2.只要S是V的真子集,就作如下的贪心选择:选取满足条件i∈S,j∈V-S,且c[i][j]最小的边,将顶点j添加到S中。

3.这个过程一直进行到S=V时为止,选取到的所有边恰好构成G的一棵最小生成树。

代码实现:

// 贪心算法 最小生成树问题 - Prim算法
#include <iostream> 
using namespace std;

#define M 9999	// maxint,inf,大数,无穷
const int N = 6;// 无向连通带权图的 顶点数

void Prim(int n, int c[][N + 1]);

int main()
{
	// 无向连通带权图的邻接矩阵,行和列下标从1开始
	int c[N + 1][N + 1] = {
		{M,	M,	M,	M,	M,	M,	M},
		{M,	M,	8,	1,	5,	M,	M},
		{M,	8,	M,	3,	M,	3,	M},
		{M,	1,	3,	M,	5,	6,	4},
		{M,	5,	M,	5,	M,	M,	2},
		{M,	M,	3,	6,	M,	M,	6},
		{M,	M,	M,	4,	2,	6,	M},
	};
	
	cout << "无向连通带权图的矩阵为:\n";
	for (int i = 1; i <= N; i++)
	{
		for (int j = 1; j <= N; j++){
		if(c[i][j]==M)
				{
					cout << "INF" << "\t";
				}
				else{
					cout << c[i][j] << "\t";
				}		
		}
		
		cout << endl;
	}

	cout << "\nPrim算法最小生成树选边次序:" << endl;
	Prim(N, c);
	
	return 0;
}

void Prim(int n, int c[][N + 1])
{
	// 顶点j属于V-S,closest[j]是顶点j在S中的 最邻接顶点
	int closest[N + 1];	// j的 最邻接顶点
	// 顶点j属于V-S,顶点j到closest[j]和S中的其它邻接顶点k相比
	// c[j][closest[j]] <= c[j][k],即最小权值
	int lowcost[N + 1];	// 最小权值,c[j][closest[j]]

	bool s[N + 1];		// 顶点集合S

	s[1] = true;		// 初始S={1}

	//初始化
	for (int i = 2; i <= n; i++)
	{
		closest[i] = 1;
		lowcost[i] = c[1][i];
		s[i] = false;
	}

	for (int i = 1; i < n; i++)
	{
		int min = M;
		int j = 1;
		// 找出V-S中使权值最小的顶点j
		for (int k = 2; k <= n; k++)
		{
			if ((lowcost[k] < min) && (!s[k]))
			{
				min = lowcost[k];
				j = k;
			}
		}
		// 找到符合贪心选择方式的边,将顶点j加入到集合S
		cout << closest[j] << "--" << j << endl;
		s[j] = true;

		// 找到一条边后,更新数组closest和lowcost
		for (int k = 2; k <= n; k++)
		{
			if ((c[j][k] < lowcost[k] && (!s[k])))
			{
				lowcost[k] = c[j][k];
				closest[k] = j;
			}
		}
	}
}

运行结果:

  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

涣清。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值