最小生成树 Prim算法实现(c语言代码)

文章描述了一个使用无向图表示城市间公路交通的问题,通过输入城市和公路信息来建立邻接矩阵,并应用普里姆算法找到最小生成树,以最小化光纤铺设成本。程序包括创建图、输入处理和最小生成树的计算过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【问题描述】

城市之间的公路交通可以用一个无向图表示。如下图所示:  

顶点表示城市、边表示城市之间有公路相连,边上的权值表示城市之间的公路长度。

编程解决以下问题:

(1)输入城市信息和城市之间公路的信息,建立图的邻接矩阵存储结构

 (2)为了使城市之间能够通信,将沿公路铺设光纤,给出合理的方案,使得光纤总耗费最小。

【输入形式】

第一行输入城市,城市之间用空格分开,输入q结束。

后面若干行,每行输入两座城市及城市间的公路长度,用空格分开。输入q结束。

输入起点城市名称。
【输出形式】起点城市出发得到的最小生成树,输出格式为(起点城市, 终点城市). 

注:城市之间是英文逗号,并且没有空格。
【样例输入】

成都 西安 昆明 贵阳 武汉 株洲 q

成都 西安 842

成都 昆明 1100

成都 贵阳 967

西安 武汉 740

贵阳 武汉 1042

贵阳 株洲 607

武汉 株洲 409

q

成都

注意事项

1. 录入边信息时,由于是无向图是对称矩阵,所以邻接矩阵对称位置都要记录边的权值。

2. 每加入一个顶点,所有未加入顶点都要更新 closedge 数组的内容。

在最后附有总的代码!!!

步骤:

一、建立图的邻接矩阵存储结构

1、定义图的数组存储的结构体类型。

#define MaxVertexNum 25 /*最大顶点数设为 25*/
#define INF 32767 		/*INF 表示∞*/
typedef int EdgeType; 	/*边的权值设为整型*/
typedef struct 			/*邻接矩阵类型定义*/
{
 char vexs[MaxVertexNum][10]; 				 /*顶点表成都,武汉...*/ 
 EdgeType edges[MaxVertexNum][MaxVertexNum]; /*邻接矩阵,即边表*/ 
 int n, e; 									 /*顶点数和边数*/
 }MGraph;

2、定义创建图的存储的函数。

/*返回顶点城市在顶点数组vexs 中序号,没有该城市名返回-1*/
int VexID(MGraph *G,char VexName[]) 
{
 int i; 
 for(i = 0; i < G -> n; i ++) 
 { 
	if(strcmp(VexName, G->vexs[i]) == 0) 
		break; 
 } 
 if(i == G->n) 
 	return -1; 
 else 
 	return i;
}

void createGraph(MGraph *G)
{
 int i, j, k, l; 
 char t[10], m[10]; 
 /*记录顶点信息*/
 printf("\n 请依次输入城市名,输入 q 退出:\n");
 for(i = 0; i < MaxVertexNum; i ++) 
 {
  	printf("\n 序号为%d的城市名称:", i); 
 	scanf("%s", G->vexs[i]); 
 	/***完善下列代码****/ /*如果输入q,退出循环*/
 	if(strcmp(G->vexs[i],"q")==0)	//比较字符串 
		break; 
 	G->n++; /*记录输入顶点数目*/	
 } 
 /*初始化邻接矩阵*/ 
/***完善下列代码****/     /*邻接矩阵主对角线上元素为0,其余为INF*/
	for(i=0;i<G->n;i++)
 	{
 		for(i=0;i<G->n;i++)
 		{
 			if(i==j)
 			{
 				G->edges[i][j] = 0;
			}
			else
				G->edges[i][j] = INF;
		}
	}
	/*记录边信息*/ 
     printf("\n 请输入边的信息,输入 q 退出:\n");    
  for(i = 0; ; i ++)                                   
   { 
	   	printf("\n 起始顶点:");   
	   	scanf("%s", t);   
	   	if(strcmp(t, "q") == 0)    
	   		break;   
	   	printf("\n 终止顶点:");   
	   	scanf("%s", m);   
	   	printf("\n 边的权重:");   
	   	scanf("%d", &l);    		
	    j = VexID(G, t);   
		k = VexID(G, m); 
	   	/***完善下列代码****/  ;/*在邻接矩阵对应位置记录边的权值*/ 
		if(j!=-1 && k!=-1)
		{
			G->edges[j][k] = l;		//无向图需要双向标记 
			G->edges[k][j] = l;	
			//G->e++;				//边数加一 
		}
		else
		{
			printf("输入的顶点信息有误!");	
			i--; 
		} 
	}  
	G->e = i;                  /*记录边的数目*/   	
}

二、编写最小生成树算法。

/*定义 Closedge 数组类型,作为普里姆算法的辅助数组类型*/
typedef struct         
{  
  int adjvex;  //目标点 
  int lowcost; //到目标点的最短距离 
}Closedge; 
/*输出最小生成树的普里姆算法。*/ 
void Prim(MGraph *G,char *startCity) 
{ /*G 为图的邻接矩阵存储,startCity 是起点城市名称*/  
  /*算法将依次输出需要铺设光缆的公路*/ 
	int k, j, i, minCost;  
	Closedge closedge[MaxVertexNum]; /*定义辅助数组*/  

	int v = VexID(G, startCity);
	if(v < 0) 
	{
		printf("输入的起点城市错误!\n");
		return;
	}
	closedge[v].lowcost = 0; 	//初始化所有的最短距离为0 
	for (j = 0; j < G->n; j ++) /*初始化 closedge 数组*/
   { /***完善下列代码****/
 		if(j!=v)		
 		{
 			closedge[j].adjvex = v;					//依此将顶点存入closedge数组 
			closedge[j].lowcost = G->edges[v][j];	//依此将边存入closedge数组 
		}	
	}	
	
	for (i = 1; i < G->n; i ++)  /*依次将顶点加入到集合 U 中*/  
	{ 
		for(j = 0; j < G->n; j++)/*定位第一个没有加入到 U 中的顶点*/    
			if(closedge[j].lowcost != 0)    
			{ 
				k = j;     
				break;    
			}			
		minCost = closedge[k].lowcost; /*定位V-U集合中 lowcost最小的顶点*/	  
		for (j = 0; j < G->n; j ++)    
			if (closedge[j].lowcost < minCost && closedge[j].lowcost != 0)             
			{
		 		/***完善下列代码****/
		 		k = j;
				minCost = closedge[j].lowcost;     
			}	
		printf("(%s,%s)\n", G->vexs[closedge[k].adjvex], G->vexs[k]);  /*输出新边加入到树中的边*/  
		/***完善下列代码****/   /*将该顶点加入到集合 U*/ 
		closedge[k].lowcost = 0; 		
		for (j = 0; j < G->n; j ++)     /*更新 closedge 数组的内容*/    
		{/***完善下列代码****/
 			if((G->edges[k][j] < closedge[j].lowcost)&& (G->edges[k][j] != 0 ))
 			{
 				closedge[j].adjvex = k;
 				closedge[j].lowcost = G->edges[k][j];
			}
		}
	}  	 
} 

三、编写主函数

int main(int argn,char *argv[])
{
	int select, i, j;
	char c[10];
	MGraph *G;
	char startCity[1024];
	G = (MGraph *)malloc(sizeof(MGraph));
	G->n = G->e = 0;
	createGraph(G);
	fflush(stdin);
	gets(startCity);//输入出发城市
	Prim(G, startCity);
	return 0;
}

总的代码

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MaxVertexNum 25 /*最大顶点数设为 25*/
#define INF 32767 		/*INF 表示∞*/
typedef int EdgeType; 	/*边的权值设为整型*/
typedef struct 			/*邻接矩阵类型定义*/
{
 char vexs[MaxVertexNum][10]; 				 /*顶点表成都,武汉...*/ 
 EdgeType edges[MaxVertexNum][MaxVertexNum]; /*邻接矩阵,即边表*/ 
 int n, e; 									 /*顶点数和边数*/
 }MGraph;
 
/*定义 Closedge 数组类型,作为普里姆算法的辅助数组类型*/
typedef struct         
{  
  int adjvex;  //目标点 
  int lowcost; //到目标点的最短距离 
}Closedge; 

 
 /*返回顶点城市在顶点数组vexs 中序号,没有该城市名返回-1*/
int VexID(MGraph *G,char VexName[]) 
{
 int i; 
 for(i = 0; i < G -> n; i ++) 
 { 
	if(strcmp(VexName, G->vexs[i]) == 0) 
		break; 
 } 
 if(i == G->n) 
 	return -1; 
 else 
 	return i;
}

void createGraph(MGraph *G)
{
 int i, j, k, l; 
 char t[10], m[10]; 
 /*记录顶点信息*/
 printf("\n 请依次输入城市名,输入 q 退出:\n");
 for(i = 0; i < MaxVertexNum; i ++) 
 {
  	printf("\n 序号为%d的城市名称:", i); 
 	scanf("%s", G->vexs[i]); 
 	/***完善下列代码****/ /*如果输入q,退出循环*/
 	if(strcmp(G->vexs[i],"q")==0)	//比较字符串 
		break; 
 	G->n++; /*记录输入顶点数目*/	
 } 
 /*初始化邻接矩阵*/ 
/***完善下列代码****/     /*邻接矩阵主对角线上元素为0,其余为INF*/
	for(i=0;i<G->n;i++)
 	{
 		for(i=0;i<G->n;i++)
 		{
 			if(i==j)
 			{
 				G->edges[i][j] = 0;
			}
			else
				G->edges[i][j] = INF;
		}
	}
	/*记录边信息*/ 
     printf("\n 请输入边的信息,输入 q 退出:\n");    
  for(i = 0; ; i ++)                                   
   { 
	   	printf("\n 起始顶点:");   
	   	scanf("%s", t);   
	   	if(strcmp(t, "q") == 0)    
	   		break;   
	   	printf("\n 终止顶点:");   
	   	scanf("%s", m);   
	   	printf("\n 边的权重:");   
	   	scanf("%d", &l);    		
	    j = VexID(G, t);   
		k = VexID(G, m); 
	   	/***完善下列代码****/  ;/*在邻接矩阵对应位置记录边的权值*/ 
		if(j!=-1 && k!=-1)
		{
			G->edges[j][k] = l;		//无向图需要双向标记 
			G->edges[k][j] = l;	
			//G->e++;				//边数加一 
		}
		else
		{
			printf("输入的顶点信息有误!");	
			i--; 
		} 
	}  
	G->e = i;                  /*记录边的数目*/   	
}


/*输出最小生成树的普里姆算法。*/ 
void Prim(MGraph *G,char *startCity) 
{ /*G 为图的邻接矩阵存储,startCity 是起点城市名称*/  
  /*算法将依次输出需要铺设光缆的公路*/ 
	int k, j, i, minCost;  
	Closedge closedge[MaxVertexNum]; /*定义辅助数组*/  

	int v = VexID(G, startCity);
	if(v < 0) 
	{
		printf("输入的起点城市错误!\n");
		return;
	}
	closedge[v].lowcost = 0; 	//初始化所有的最短距离为0 
	for (j = 0; j < G->n; j ++) /*初始化 closedge 数组*/
   { /***完善下列代码****/
 		if(j!=v)		
 		{
 			closedge[j].adjvex = v;					//依此将顶点存入closedge数组 
			closedge[j].lowcost = G->edges[v][j];	//依此将边存入closedge数组 
		}	
	}	
	
	for (i = 1; i < G->n; i ++)  /*依次将顶点加入到集合 U 中*/  
	{ 
		for(j = 0; j < G->n; j++)/*定位第一个没有加入到 U 中的顶点*/    
			if(closedge[j].lowcost != 0)    
			{ 
				k = j;     
				break;    
			}			
		minCost = closedge[k].lowcost; /*定位V-U集合中 lowcost最小的顶点*/	  
		for (j = 0; j < G->n; j ++)    
			if (closedge[j].lowcost < minCost && closedge[j].lowcost != 0)             
			{
		 		/***完善下列代码****/
		 		k = j;
				minCost = closedge[j].lowcost;     
			}	
		printf("(%s,%s)\n", G->vexs[closedge[k].adjvex], G->vexs[k]);  /*输出新边加入到树中的边*/  
		/***完善下列代码****/   /*将该顶点加入到集合 U*/ 
		closedge[k].lowcost = 0; 		
		for (j = 0; j < G->n; j ++)     /*更新 closedge 数组的内容*/    
		{/***完善下列代码****/
 			if((G->edges[k][j] < closedge[j].lowcost)&& (G->edges[k][j] != 0 ))
 			{
 				closedge[j].adjvex = k;
 				closedge[j].lowcost = G->edges[k][j];
			}
		}
	}  	 
} 



int main(int argn,char *argv[])
{
	int select, i, j;
	char c[10];
	MGraph *G;
	char startCity[1024];
	G = (MGraph *)malloc(sizeof(MGraph));
	G->n = G->e = 0;
	createGraph(G);
	fflush(stdin);
	gets(startCity);//输入出发城市
	Prim(G, startCity);
	return 0;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值