利用最小生成树算法解决通信网的总造价最低问题(设计性实验)

利用最小生成树算法解决通信网的总造价最低问题(设计性实验)

1. 需求分析

需求:
若在n个城市之间建通信网络,只需架设n−1条线路即可。如何以最低的经济代价建设这个通信网是一个网的最小生成树问题。
基本要求
以邻接表为存储结构,利用Prim算法或Kruskal算法求网的最小生成树。

  1. 输入的形式和输入值的范围:图类型,点数,边数,权值
  2. 输出的形式:打印最小生成树的边
  3. 程序所能达到的功能:利用Prim算法求图的最小生成树并打印
  4. 测试数据:
    UDG 9 15
    A B C D E F G H I
    AB11 AF20 BG3 BC45 CD33 BI67 CI56 DI15 DG44 DH14 DE22 EH48 EF44 FG1 GH17

2. 概要设计

  1. 为了实现程序功能,需要定义图的抽象数据类型。
ADT:图(Graph) 
Data:顶点的有穷非空集合和边集合 
typedef struct ArcNode{
	int adjvex;
	int weigth; 
	struct ArcNode *nextarc;
}ArcNode;    //邻接表结构 

typedef struct VNode{
	VertexType vexdata;
	ArcNode *firstarc;
}VNode;    //点节点 

typedef struct{
	VNode *vertices;
	int vexnum;
	int arcnum;
	GraphKind kind[4];
}ALGraph;   //图结构 

typedef struct{
	int first;
	int tail;
	int weigth;
}edge;   // 边结构
Operation:
Graph(V):按照顶点集 VV 初始化图。
addVex(v):在图 G 中添加新顶点 vv。
deleteVex(v):删除图 G 中顶点 vv 及其相关弧。
addEdge(v1,v2):在图 G 中添加弧<v1,v2><v1,v2>,若 G 是无向图,则还需要增添对称弧 <v2,v1><v2,v1>deleteEdge(v1,v2):在图 G 中删除弧<v1,v2><v1,v2>,若 G 是无向图,则还需要删除对称弧 <v2,v1><v2,v1>DFSTraverse(v):从顶点 vv 开始对图 G 进行深度优先遍历。
BFSTraverse(v):从顶点 vv 开始对图 G 进行广度优先遍历。

3. 具体代码

  • 图.h:
#define VertexType char
#define GraphKind char
#define TRUE 1
#define FALSE 0

typedef struct ArcNode{
	int adjvex;
	int weigth; //权值 
	struct ArcNode *nextarc;
}ArcNode;    //邻接表结构 

typedef struct VNode{
	VertexType vexdata;
	ArcNode *firstarc;
}VNode;    //点节点 


typedef struct{
	VNode *vertices;
	int vexnum;
	int arcnum;
	GraphKind kind[4];
}ALGraph;   //图结构 

typedef struct{
	int first;//头 
	int tail;//尾 
	int weigth;
}edge;   // 边结构 

int LocateVex(ALGraph *a,char ch)   //查找节点 
{
	int i = 0; 
	for(;i < a->vexnum;++i)
	{
		if(a->vertices[i].vexdata == ch)
		{
			return i;
		}
	}
	exit(-1);
}

void CreateGraph(ALGraph *a,FILE *r)    //创建图 
{
	char ch;
    fscanf(r,"%s",&a->kind[0]);
	fscanf(r,"%c",&ch);
	fscanf(r,"%d %d",&a->vexnum,&a->arcnum);
	fscanf(r,"%c",&ch);
	a->vertices = (VNode*)malloc(a->vexnum * sizeof(VNode));
	int i = 0;
	for(;i < a->vexnum;++i)
	{
		fscanf(r,"%c",&a->vertices[i].vexdata);
		fscanf(r,"%c",&ch);
		a->vertices[i].firstarc = NULL;
	}
	i = 0;
	for(;i < a->arcnum;++i)
	{
		char sv,tv;
		int we;
		fscanf(r,"%c%c%d",&sv,&tv,&we);
		fscanf(r,"%c",&ch);
		int j = LocateVex(a,sv);
		int k = LocateVex(a,tv);
		ArcNode *p = (ArcNode*)malloc(sizeof(ArcNode));
		p->adjvex = k;
		p->weigth = we;
		p->nextarc = a->vertices[j].firstarc;
		a->vertices[j].firstarc = p;
		if(a->kind[0] == 'U'&&a->kind[1] == 'D')
		{
			ArcNode *q = (ArcNode*)malloc(sizeof(ArcNode));
			q->adjvex = j;
			q->weigth = we;
			q->nextarc = a->vertices[k].firstarc;
			a->vertices[k].firstarc = q;
		} 
	}
}

void MiniSpanTree_PRIM(ALGraph a,edge *e)    //Prim算法求最小生成树 
{
	//U为最小生成树的顶点集,TE为最小生成树的边集。
	int U[a.vexnum],number = 0,judge[a.vexnum];//U数组装顶点,judge做判断顶点 
	int n = 0;//用于for循环 
	for(;n < a.vexnum;n++)//遍历所有judge,全部赋值为-1 
	{
		judge[n] = -1;
	}
	U[number++] = 0;//u[0]=0,number++ 
	judge[U[number-1]] = 0;//judge[0]=0 
	for(;number <= a.vexnum;number++)//number从1开始 //每次循环返回一个边结构,一共返回 
	{
		edge j;//创建一个边结构 
		j.tail = -1;//边的尾先设为空 
		int i = 0;//用于for循环 
		for(;i < number;i++)//遍历所有节点 
		{
			ArcNode *p = a.vertices[U[i]].firstarc;//用于for循环 , U中的所有节点
			for(;p != NULL;p = p->nextarc)//遍历该节点得所有邻接节点 
			{
				if(judge[p->adjvex] == -1)//如果未进入U数组 
				{
					j.tail = p->adjvex;//边尾就是这个邻接节点 
					j.first = U[i];//边头部就是这个节点 
					j.weigth = p->weigth;//边的权值 
					break;
				}
			}
			if(j.tail != -1)//如果边已经有主了,跳出for循环 
			{
				break;
			}
		}
		i = 0;//用于for循环 
		for(;i < number;i++)//遍历所有节点 
		{
			ArcNode *p = a.vertices[U[i]].firstarc;//用于for循环, U中的所有节点 
			for(;p != NULL;p = p->nextarc)遍历该节点得所有邻接节点 
			{
				if(judge[p->adjvex] == -1&&p->weigth <= j.weigth)//更新节点,如果有权值更少的 
				{
					j.tail = p->adjvex;// 
					j.first = U[i];
					j.weigth = p->weigth;
				}
			}
		}
		U[number] = j.tail;
		judge[U[number]] = 0;
		e[number-1] = j;//把j放入 
	}
}
  • 主程序.c:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"图.h"
 
 //使用算法为prim算法
  
int main() 
{
    FILE *r,*w;
    printf("请将数据放入文件'data.txt'中。(放好请按ENTER键继续)");
    getchar();
    if((r = fopen("data.txt","r")) == NULL)
	{
	    exit(-1);
	}
    if((w = fopen("result.txt","w")) == NULL)
	{
	    exit(-1);
	}	
	ALGraph graph;
	CreateGraph(&graph,r);
	edge e[graph.vexnum - 1];
	MiniSpanTree_PRIM(graph,e);
	//MiniSpanTree_PRIM(&graph,e);
	fprintf(w,"要架设的路线分别是:\n");
	int i = 0;
	for(;i < (graph.vexnum - 1);i++)
	{
		fprintf(w,"%c%c ",graph.vertices[e[i].first].vexdata,graph.vertices[e[i].tail].vexdata);
	} 
	printf("结果已放入文件'result.txt'中。");
	return 0;
} 

4. 相关数据

  • data.txt

UDG 7 12
A B C D E F G
AB2 AC4 AD1 BD3 CD2 BE10 DE7 CF5 DF8 DG4 EG6 FG1

  • 初始图
    在这里插入图片描述
  • 最小生成树
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值