C语言Prim算法最小树算法

普里姆算法Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小。该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vojtěch Jarník)发现;并在1957年由美国计算机科学家罗伯特·普里姆(英语:Robert C. Prim)独立发现;1959年,艾兹格·迪科斯彻再次发现了该算法。因此,在某些场合,普里姆算法又被称为DJP算法、亚尔尼克算法或普里姆-亚尔尼克算法。

算法描述:

1).输入:一个加权连通图,其中顶点集合为V,边集合为E;

2).初始化:Vnew = {x},其中x为集合V中的任一节点(起始点),Enew = {},为空;

3).重复下列操作,直到Vnew = V:

a.在集合E中选取权值最小的边<u, v>,其中u为集合Vnew中的元素,而v不在Vnew集合当中,并且v∈V(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一);

b.将v加入集合Vnew中,将<u, v>边加入集合Enew中;

4).输出:使用集合Vnew和Enew来描述所得到的最小生成树

prim算法函数如下

void Prim(Graph G)
{
    int v=0;//初始节点
    closedge C[MaxVerNum];
    int mincost = 0; //记录最小生成树的各边权值之和
    //初始化
    for (int i = 0; i < G.vexnum; i++)
    {
        C[i].adjvex = v;
        C[i].lowcost = G.Edge[v][i];
    }
    cout << "最小生成树的所有边:"<< endl;
    //初始化完毕,开始G.vexnum-1次循环
    for (int i = 1; i < G.vexnum; i++)
    {
    int k;
    int min = INF;
    //求出与集合U权值最小的点 权值为0的代表在集合U中
    for (int j = 0; j<G.vexnum; j++)
    {
    if (C[j].lowcost != 0 && C[j].lowcost<min)
    {
    min = C[j].lowcost;
    k = j;
    }
    }
    //输出选择的边并累计权值
    cout << "(" << G.Vex[k] << "," << G.Vex[C[k].adjvex]<<") ";
    mincost += C[k].lowcost;
    //更新最小边
    for (int j = 0; j<G.vexnum; j++)
    {
    if (C[j].lowcost != 0 && G.Edge[k][j]<C[j].lowcost)
    {   
    C[j].adjvex = k;
    C[j].lowcost= G.Edge[k][j];
}
}
 
}
cout << "最小生成树权值之和:" << mincost << endl;
}

所有代码:

#include <stdio.h>
#include<stdlib.h>
#include <string.h>
#define MaxVerNum 100
#define MaxVertexNum  100 
#define INF 32767
typedef int VertexType;   //顶点的数据类型
typedef int EdgeType;     //带权图中边上权值的数据类型
typedef struct closedge
{
    int adjvex;     //最小边在集合U(最小边在当前子树顶点集合中的那个顶点的下标)
    int lowcost;    //最小边上的权值
};

typedef struct
{
	VertexType Vex[MaxVertexNum];   //顶点表
	EdgeType Edge[MaxVertexNum][MaxVertexNum];  //邻接矩阵,边表
	int vexnum, edgenum;    //图的顶点数和弧数
}MGraph;

/***********创建有向图*·***********/
void create_Graph2(MGraph *G)
{
	int i, j;
	int start, end;  //边的起点序号、终点序号
	int numV, numE;
	int w;   //边上的权值
	printf("请输入所创建有向图的顶点数和边数(用空格隔开):");
	scanf("%d%d", &numV, &numE);
	G->vexnum = numV;
	G->edgenum = numE;
	printf("\n");
	//图的初始化
	for (i = 0; i < G->vexnum; i++)
	{
		for (j = 0; j < G->vexnum; j++)
		{
			if (i == j)
				G->Edge[i][j] = 0;
			else
				G->Edge[i][j] = 32767;
		}
	}
	//顶点信息存入顶点表
	for (i = 0; i < G->vexnum; i++)
	{
		printf("请输入第%d个顶点的信息:", i + 1);
		scanf("%d", &G->Vex[i]);
	}
	printf("\n");
	//输入无向图边的信息
	for (i = 0; i < G->edgenum; i++)
	{
		printf("请输入边的起点序号,终点序号,权值(用空格隔开):");
		scanf("%d%d%d", &start, &end, &w);
		G->Edge[start - 1][end - 1] = w;   //有向图只在这里不一样
		G->Edge[end - 1][start - 1] = w;
	}
}
void Prim(MGraph G)
{
    int v=0;//初始节点
    closedge C[MaxVerNum];
    int mincost = 0; //记录最小生成树的各边权值之和
    //初始化
    for (int i = 0; i < G.vexnum; i++)
    {
    C[i].adjvex = v;
    C[i].lowcost = G.Edge[v][i];
    }
    
    //初始化完毕,开始G.vexnum-1次循环
    for (int i = 1; i < G.vexnum; i++)
    {
        int k;
        int min = INF;
    //求出与集合U权值最小的点 权值为0的代表在集合U中
    for (int j = 0; j<G.vexnum; j++)
    {
    if (C[j].lowcost != 0 && C[j].lowcost<min)
    {
        min = C[j].lowcost;
        k = j;
    }
}
//输出选择的边并累计权值
    mincost += C[k].lowcost;
    //更新最小边
    for (int j = 0; j<G.vexnum; j++)
    {
    if (C[j].lowcost != 0 && G.Edge[k][j]<C[j].lowcost)
    {   
        C[j].adjvex = k;
        C[j].lowcost= G.Edge[k][j];
}
}
 
}
    printf("最小生成树权值之和");
    printf("%d",mincost);
}

int main(){
    MGraph G;
	create_Graph2(&G);
    Prim(G);
	return 0;
}

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值