图的应用1.最小生成树——prim算法实现(加点法)

最小生成树
概念:将给出的所有点连接起来(即从一个点可到任意一个点),且连接路径之和最小的图叫最小生成树。
数据结构:树形结构,或者说是直链型结构,因为当n个点相连,且路径和最短,那么将它们相连的路一定是n-1条
实现思路:将点分为在树中的点与不在树中的点,每次取出树中点的连接的最小路径,且该路径连接的点不在树中,然后将该路径连接的点加入树中,重复并进行路关于图的几个概念定义:
连通图:在无向图中,若任意两个顶点vivi与vjvj都有路径相通,则称该无向图为连通图。
强连通图:在有向图中,若任意两个顶点vivi与vjvj都有路径相通,则称该有向图为强连通图。
连通网:在连通图中,若图的边具有一定的意义,每一条边都对应着一个数,称为权;权代表着连接连个顶点的代价,称这种连通图叫做连通网。
生成树:一个连通图的生成树是指一个连通子图,它含有图中全部n个顶点,但只有足以构成一棵树的n-1条边。一颗有n个顶点的生成树有且仅有n-1条边,如果生成树中再添加一条边,则必定成环。
最小生成树:在连通网的所有生成树中,所有边的代价和最小的生成树,称为最小生成树。 径更新,即松弛,当取出边达到n-1条时,树已建立。

#include<iostream>
using namespace std;
//用邻接矩阵来存储
#define MaxNum 10//最大顶点数
#define MaxInt 32767//无穷大
#define MinInt -1//认为较小
typedef char  VerType;//数据类型
typedef int ArcType;//权值类型
//定义图的结构
typedef struct {
	VerType ver[MaxNum];//顶点表
		ArcType arc[MaxNum][MaxNum];//邻接矩阵
		int vernum, arcnum;	//点数,边数
}AMGraph;
//定位
int Locate(AMGraph G, VerType v1) {
	for(int i = 0; i < G.vernum; i++) {
		if (G.ver[i] == v1) {
			return i;
		}
	}
	return -1;
}
//创建无向图
bool createUDN(AMGraph &G) {
	cout << "Please input the vernum and arcnum" << endl;
	cin >> G.vernum >> G.arcnum;
	cout << "Please input the name of points" << endl;
	int i = 0,j=0;
	for ( i = 0; i < G.vernum; i++)
		cin >> G.ver[i];
	//初始化邻接矩阵
	for (i = 0; i < G.vernum; i++) {
		for (j = 0; j < G.vernum; j++) {
			if (i != j)
				G.arc[i][j] = MaxInt;
			else G.arc[i][j] = 0;
		}
	}
	//开始操作,构造邻接表
	cout << "Please input arcnum graph " << endl;
	VerType v1, v2;
	ArcType w;
	int p, q;
	for (i = 0; i < G.arcnum; i++) {
		cin >> v1 >> v2 >> w;
		p = Locate(G, v1); q = Locate(G, v2);
		G.arc[p][q] = w;
		G.arc[q][p] = G.arc[p][q];
	}
	return true;
}
void show(AMGraph G) {
	int i, j;
	for (i = 0; i < G.vernum; i++) {
		for (j = 0; j < G.vernum; j++) {
			if (G.arc[i][j] == MaxInt)  printf("INF\t");
			else printf("%-3d\t", G.arc[i][j]);
		}
		cout << endl;
	}
}

// Prim算法部分

//辅组数组,记录U到V-U具有最小权值的边,入U的标准是lowCost=0(U是最小路径解集)

struct closedge {
	VerType point;
	ArcType lowCost;//worth of road
}closeEdge[ MaxNum ];

//思想:U是最小路径解集
//1.首先,把初始顶点u加入U中,对其余的每一个顶点vj,将closeEdge[j]均初始化为到u的边的信息。
//2.循环(n-1)次,循环内容:
// 从剩下没选过的各组边closeEdge[]中选择最小边closeEdge[K],输出此边
// 将k加入U中
// 更新剩余的每组边的最小边信息close[j],对于V-U中的边,新增加了一个j-k的边,如果这条边小于closeEdge[j],则更新为前者的值

int Min(closedge a[],int n) {
	int mark = 0, min = MaxInt;
	for (int i = 0; i < n; i++) {
		if (a[i].lowCost!=0 && min > a[i].lowCost) {
			mark = i;
			min = a[i].lowCost;
		}
	}
	return mark;
}
void MiniSpanTree_Prim(AMGraph G, VerType u) {
	int k = Locate(G, u);		//k为u下标
	int j = 0;
	//初始化closeEdge数组
	for ( j = 0; j < G.vernum; j++)
		if (j != k) 
			closeEdge[j] = { u,G.arc[k][j] };
	closeEdge[k].lowCost = 0;//初始化到现在,U={u},入U的标准是lowCost=0
	VerType  u0=0; //最小边的顶点
	VerType v0=0;//最小边的另一个顶点
	for (int i = 1; i < G.vernum; i++) {//选择剩下的(n-1)个顶点,生成(n-1)条边
		k = Min(closeEdge, G.vernum);
		u0 = closeEdge[k].point;//最小边的顶点,属于U
		v0 = G.ver[k];			//最小边的另一个顶点,属于V-U
		//把v0融于U
		closeEdge[k].lowCost = 0;
		cout <<"the small arc begin at point " <<u0 << " ,and end at point " << v0 << endl;
		//更新剩余的每组边的最小边信息close[j],对于V-U中的边,新增加了一个j-k的边,如果这条边小于closeEdge[j],则更新为前者的值
		for (j = 0; j < G.vernum; j++) {	//剩下的点到k值与原来的值比较
			if (G.arc[k][j] < closeEdge[j].lowCost) {
				closeEdge[j].lowCost = G.arc[k][j];//边值交换,新点进入U后,为了方便重新选择最小边
				closeEdge[j].point = G.ver[k];//存放的是点的名字
			}
		}
	}
}
int main() {
	AMGraph G;
	createUDN(G);
	// show(G);
	cout << "Please input the initial point:" << endl;
	VerType u; cin >> u;
	MiniSpanTree_Prim(G, u);
}

/*
测试案例
7 9
0 1 2 3 4 5 6
0 1 28
0 5 10
1 2 16
1 6 14
5 4 25
4 6 24
4 3 22
2 3 12
3 6 18
*/

/*
7 9
a b c d e f g
a b 28
a f 10
b c 16
b g 14
f e 25
e g 24
e d 22
c d 12
d g 18
*/
prim算法时间复杂度尾O(n^2),与网的边数没有关系,适合求稠密网的最小生成树。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

广大菜鸟

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

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

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

打赏作者

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

抵扣说明:

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

余额充值