C语言详细分析贪心策略中最小生成树的Prime算法设计与实现

目录
  • 浅析最小生成树
  • Prime算法思想
  • 此算法核心部分
    • 结构体的选择
    • 实现思路
  • 构造实例
  • 构造过程
  • 代码详解
  • 调试结果
  • 总结

浅析最小生成树

设G=(V,E)是无向连通带权图。E中每条边(v,w)的权为c[v][w]。

生成树:如果G的子图G’是一棵包含G的所有顶点的树,则称G’为G的生成树。

耗费:生成树上各边权的总和

最小生成树:在G的所有生成树中,耗费最小的生成树最小生成树在实际中有广泛应用。

例如,在设计通信网络时,用图的顶点表示城市,用边(v,w)的权c[v][w]表示建立城市v和城市w之间的通信线路所需的费用,则最小生成树就给出建立通信网络的最经济的方案。

Prime算法思想

牵扯到贪心策略

设G=(V,E)是无向连通带权图,V={1,2,…,n};

设最小生成树T=(U,TE),算法结束时U=V,TE E。

首先,令U={u0},TE={}。然后,只要U是V的真子集,就做如下贪心选择:选取满足条件i U,j V-U,且边(i,j)是连接U和V-U的所有边中的最短边,即该边的权值最小。然后,将顶点j加入集合U,边(i,j)加入集合TE。继续上面的贪心选择一直进行到U=V为止,此时,选取到的所有边恰好构成G的一棵最小生成树T。需要注意的是,贪心选择这一步骤在算法中应执行多次,每执行一次,集合TE和U都将发生变化,即分别增加一条边和一个顶点。

此算法核心部分

结构体的选择

选择一个合适的数据结构可以让程序的实现效率大大提高,难度大大降低;既然是生成最小生成树,不妨选择点和边结构体;因此创建两个结构体,第一个点node结构体包含所有的结点;第二个边结构体包含所有待选择的边、连接点及权值。

实现思路

tips:onTreet 属性是布尔类型,为true时该结点在“树”上

首先对应第一个结点找我们需要的边,我们需要什么样的边呢,那就是在边的两个连接点中,有且仅有一个连结点等于结点的名称(这个可以在点结构体中加ID属性),并且这个结点必须是根结点(即onTree为true),满足这个条件,就把另一个连接点的onTree属性设为true;最后为了把满足条件的边连起来,我就个边结构体也加一个onTree属性,输出所有onTree 为true的边结构体即可。

构造实例

按Prim算法对如图所示的无向连通带权图构造一棵最小生成树。

构造过程

点和边结构体数组图示如上所示,我们需要的最终效果为下图所示:

代码详解

#include <iostream>
using namespace std;
struct Node {
	int ID;//结点序号
	bool OnTree;//是否属于最小生成树
};
struct LS {
	int N1, N2; int V; bool OnTree;//OnTree用于判断此边是否在“树”上
	LS(int n1, int n2, int v) {
		N1 = n1; N2 = n2; V = v; OnTree = false;//N1,N2为边左右连接点,v是边的权值
	}
};
Node A[] = { {1,false}, {2,false}, {3,false}, {4,false}, {5,false} };//点结构体数组
LS L[8] = { LS(1,2,1),LS(1,3,4) ,LS(2,3,2),
LS(2,5,2),LS(4,5,4),LS(3,4,6),LS(3,5,3),LS(1,4,8)};//边结构体数组
bool FindOne(LS L ,Node A[]) {//布尔类型
	int m = 0;
	for (int i = 0; i < 5; i++)
		if (L.N1 == A[i].ID && A[i].OnTree) m++;
	for (int i = 0; i < 5; i++)
		if (L.N2 == A[i].ID && A[i].OnTree) m++;
	return m ==1;//只有N1和N2的一个连接到了在“树”上的结点才为真
}
int main()
{
	A[0].OnTree = true;
	for (int i = 0; i < 5; i++) {
		int p = 0;
		for (int j = 0; j < 8; j++) {
			if (FindOne(L[j], A)) {
				p = j; break;
			}
		}
		for (int i = 0; i < 8; i++) {
			if (FindOne(L[i], A))
				if (L[i].V < L[p].V) p = i;
		}
		L[p].OnTree = true;//选中的边设置为在“树”上
        //将边的连接点放在“树”上
		for (int i = 0; i < 5; i++) {
			if (L[p].N1 == A[i].ID) A[i].OnTree = true;
			if (L[p].N2 == A[i].ID) A[i].OnTree = true;
		}
	}
    //输出最小生成树所有边
	for (int i = 0; i < 8; i++) {
		cout << L[i].OnTree;
	}
}

结构体node 和结构体LS在上文已经较为详细的介绍了,而且还给出了node数组A和LS数组L的图示,不过要注意默认的边都是不在“树”上的;

主函数一共有四个for循环,最后一个for循环仅仅就是为了输出在最小生成树上的边,和prime的核心没有关系;

第一个for循环也就是最大的for循环,用来确定生成最小生成树的找边次数;

第二个for循环是为了找出我们所需要的边,如果存在一条边,有且仅有一个连结点等于结点的名称并且该连接点是在“树”上的,那么返回改边下标并用变量p记录;

第三个for循环是为了筛选出所有满足此条件边中权值最小的边,并把该边的小标用p记录;将最终选出的边放在“树”上,利用第三个for循环把与该边连接的点都放在“树”上,然后循环执行上述过程,直到没有满足条件的边,大循环结束,输出最小生成树。

这里详细的解析一下FindOne函数:

bool FindOne(LS L ,Node A[]) {//布尔类型
	int m = 0;
	for (int i = 0; i < 5; i++)
		if (L.N1 == A[i].ID && A[i].OnTree) m++;
	for (int i = 0; i < 5; i++)
		if (L.N2 == A[i].ID && A[i].OnTree) m++;
	return m ==1;//只有N1和N2的一个连接到了在“树”上的结点才为真
}
//调用方法 : FindOne(L[j], A)

调用该函数的时候,实参第一个是边结构体类型的L数组内的任意一个元素,第二个则是点结构体类型的A数组的首地址,所以形参第一个需要传入LS类型的变量L,第二个则是整个Node类型的数组,这样传参才相互对应,如果对于函数传参有疑问,可以参考这篇函数的传参方式然后定义变量m初始值为0,第一个for循环是和该边的第一个连接点作比较,满足条件则m+1;第二个for循环是和该边第二个连接点作比较,满足条件也会加m也会加1;但是我只要比较结果为一的m,这样就能筛选出满足条件的边。

调试结果

第一次循环,满足条件的最小权值边下标应为0(p为0),初始值第一个结点默认放在“树”上;由于p为0,所以第一个边的两个连接点都会被放在“树”上;(ID1和2都是true)

第二次循环,p为2,数组中第三条边左右连接点对应的ID2和3都会变为true;

​​​​​​第三次循环,p为3,同理,ID5会变成true;

接下来重复上面的过程,直到没有满足条件的边,循环结束;

最后就是输出所有在“树”上的边了,数组中为1的边就是被选中的边,这样清晰的得到了最终的最小生成树了。

总结

Prime算法属于贪心算法的一种,尽情的找到权值最小的边并连接到一起,最小生成树的算法分享与实现圆满完成了,希望对大家有实质性的帮助

到此这篇关于C语言详细分析贪心策略中最小生成树的Prime算法设计与实现的文章就介绍到这了,更多相关C语言Prime算法内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++超详细讲解贪心策略的设计及解决会场安排问题

    目录 问题描述 贪心策略 算法设计 代码实现 选择结构体 随机输入会议 按结束时间排序 最终会议确定 结束语 问题描述 设有n个会议的集合C={1,2,…,n},其中每个会议都要求使用同一个资源(如会议室),而在同一时间内只能有一个会议使用该资源.每个会议i都有要求使用该资源的起始时间bi和结束时间ei,且bi < ei .如果选择了会议i使用会议室,则它在半开区间[bi, ei)内占用该资源.如果[bi, ei)与[bj , ej)不相交,则称会议i与会议j是相容的.会场安排问题要求在所给的会

  • C语言详细分析贪心策略中最小生成树的Prime算法设计与实现

    目录 浅析最小生成树 Prime算法思想 此算法核心部分 结构体的选择 实现思路 构造实例 构造过程 代码详解 调试结果 总结 浅析最小生成树 设G=(V,E)是无向连通带权图.E中每条边(v,w)的权为c[v][w]. 生成树:如果G的子图G’是一棵包含G的所有顶点的树,则称G’为G的生成树. 耗费:生成树上各边权的总和 最小生成树:在G的所有生成树中,耗费最小的生成树最小生成树在实际中有广泛应用. 例如,在设计通信网络时,用图的顶点表示城市,用边(v,w)的权c[v][w]表示建立城市v和城

  • C语言详细分析浮点数在内存中的储存

    目录 浮点数的储存格式 初步了解 深入探究 E不全为0或不全为1 E全为0 E全为1 浮点数的储存格式 初步了解 首先让我们通过一段代码来认识一下浮点型和整型的区别: int main() { int n = 9;//将整型9存储到n中 float* pFloat = (float*)&n; printf("n的值为:%d\n", n); printf("*pFloat的值为:%f\n", *pFloat); *pFloat = 9.0;//将浮点型9.0存

  • C语言详细分析不同类型数据在内存中的存储

    目录 数据类型的介绍 类型的基本归类 整形在内存中的存储 大小端介绍 一道笔试题 浮点数在内存中的存储 浮点数存储规则 剖析题目 数据类型的介绍 在我们之前的学习当中我们已经介绍了基本的内置类型 char 字符数据类型 short 短整型 int 整形 long 长整型 long long 更长的整形 float 单精度浮点数 double 双精度浮点数 这些类型的意义是: 1.使用这个类型开辟内存空间的大小,大小决定了使用范围 2.如何看待内存空间的视角. 类型的基本归类 整形 整形中分为有符

  • C语言详细分析常见字符串函数与模拟实现

    目录 一. strlen(求长度) 二. strcpy(拷贝) 三.strcat(追加) 四.strcmp 五.strncpy 六.strncat 七.strncmp 八.strstr 九.strtok 十.strerror 十一.memcpy 十二.memmove 十三.memcmp 十四.memset 一. strlen(求长度) size_t  strlen ( const char * str ) 函数的返回值类型为size_t,为无符号数,且strlen返回值为字符串中‘\0’前的字符

  • C语言 详细分析结构体的内存对齐

    目录 一.结构体 二.结构体内存对齐 1.非嵌套结构体的大小 2.含嵌套结构体的大小 三.为什么要内存对齐 1.平台原因(移植原因) 2.性能原因 一.结构体 结构体 (struct)是一种数据结构,可以包含很多数据类型,可以实现比较复杂的数据结构. 常见的int,char类型变量,我们可以一眼看出占多少字节,但对于结构体,可就有点难度了. 让我们来猜猜以下程序的输出 struct S1 { char c1; int i; char c2; }; struct S2 { char c1; cha

  • C语言详细分析讲解struct与union使用方法

    目录 一.struct 的小秘密 二.结构体与柔性数组 三.C语言中的 union 四.小结 一.struct 的小秘密 C语言中的 struct 可以看作变量的集合 struct 的问题:空结构体占用多大内存?下面编写程序看一下吧: #include <stdio.h> struct TS { }; int main() { struct TS t1; struct TS t2; printf("sizeof(struct TS) = %d\n", sizeof(stru

  • C语言详细分析宏定义的使用

    目录 一.C语言中函数的“缺陷” 二.再次理解函数 三.C语言中的宏 四.宏与函数的不同 五.编译器组成简介 六.宏使用示例 七.再论宏常量 八.小结 一.C语言中函数的“缺陷” 实参和形参之间仅仅是值传递,因此,函数中无法直接改变实参. 二.再次理解函数 函数是一种代码复用的手段 把实现某个功能的代码片段进行封装(当作一个整体) 给这个代码片段一个合适的名字(通过名字使用代码) 定义参数(定义代码片段需要处理的问题) 三.C语言中的宏 宏是C语言中代码复用的补充方式 宏定义语法:#define

  • C语言详细分析讲解多文件的程序设计

    目录 一.多文件与编译器链接 二.多文件之间的相互访问 三.关于#include 四.头文件使用的一些原则 五.再论全局变量 六.注意事项 七.实验程序 八.小结 一.多文件与编译器链接 如下图所示,.o 为目标文件,链接器将不同的目标文件装配组合在一起形成一个可执行文件. 二.多文件之间的相互访问 每个文件可以定义功能接口(可被其它文件访问的函数或数据) 源文件:代码实现文件,后缀为.c 头文件:源文件的接口定义文件,后缀为.h 当需要使用其它文件提供的功能时,包含对应的头文件 语法: #in

  • C语言详细分析讲解关键字enum与sizeof及typedef的用法

    目录 一.枚举类型的使用方法 二.sizeof 关键字的用法 三.typedef 的意义 四.小结 一.枚举类型的使用方法 enum 是 C 语言中的一种自定义类型 enum 值是可以根据需要自定义的整型值 第一个定义的 enum 值默认为 0 默认情况下的 enum 值是在前一个定义值的基础上加 1 enum 类型的变量只能取定义时的离散值 enum 中定义的值是C语言中真正意义上的常量 在工程中 enum 多用于定义整型常量 下面看一段 enum 的使用代码吧: #include<stdio

随机推荐