课设-最小生成树问题

最小生成树问题

1.问题描述

[题目描述]

若要在n个城市之间建设通信网络,只需要假设n-1条线路即可。如何以最低的经济代价建设这个通信网,是一个网的最小生成树问题。

 [基本要求]

(1)利用克鲁斯卡尔算法求网的最小生成树。

(2)利用普里姆算法求网的最小生成树。

(3)要求输出各条边及它们的权值。

[测试数据]

由学生任意指定,但报告上要求写出多批数据测试结果。

[实现提示]

通信线路一旦建成,必然是双向的。因此,构造最小生成树的网一定是无向网。设图的顶点数不超过30个,并为简单起见,网中边的权值设成小于100的整数,可利用C语言提供的随机函数产生。

图的存储结构的选取应和所作操作相适应。为了便于选择权值最小的边,此题的存储结构既不选用邻接矩阵的数组表示法,也不选用邻接表,而是以存储边(带权)的数组表示图。

 [进阶]

利用堆排序实现选择权值最小的边。

2.需求分析

typedef char VerTexType;

typedef int ArcType;

typedef struct

{

    VerTexType vex[MVNum];//顶点表

    ArcType arcs[MVNum][MVNum];//邻接矩阵

    int vexnum,arcnum;//图的当前点数和边数

}AMGraph;

struct

{

    VerTexType Head;//边的始点

    VerTexType Tail;//边的终点

    ArcType lowcost;//边上的权值

}Edge[MVNum];

typedef struct Closedge

{

    VerTexType adjvex;//最小边在U中的那个顶点

    ArcType lowcost;//最小边上的权值

}closedge[MVNum];

3.算法设计

1. LocateVex(AMGraph &G,VerTexType u) //存在则返回u在顶点表中的下标;否则返回-1

2. CreatUDN(AMGraph &G)//创建图

3. Min(closedge SZ,AMGraph G)//求出第k个顶点,closedge[k]中存有当前最小边 

4. prim(AMGraph G,VerTexType u)//p算法

5. kruskal(AMGraph G)//k算法

4.调试分析

分别采用了prim算法和kruskal算法求最小生成树,参照书上的代码,有些许不懂,继续取网上查找,最后完成了这个题目。

5.实验结果

#include<stdio.h>
#include<string.h>
#include<malloc.h>
#include <stdlib.h>
#include<iostream>
using namespace std;
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status;
typedef int Boolean;
typedef char TElemType;
#define MaxInt 32767
#define MVNum 100
typedef char VerTexType;
typedef int ArcType;
typedef struct
{
	VerTexType vex[MVNum];//顶点表 
	ArcType arcs[MVNum][MVNum];//邻接矩阵 
	int vexnum,arcnum;//图的当前点数和边数 
}AMGraph;
struct
{
	VerTexType Head;//边的始点 
	VerTexType Tail;//边的终点 
	ArcType lowcost;//边上的权值 
}Edge[MVNum];
int LocateVex(AMGraph &G,VerTexType u)
{//存在则返回u在顶点表中的下标;否则返回-1
   int i;
   for(i=0;i<G.vexnum;++i)
     if(u==G.vex[i])
       return i;
   //return -1;
}
Status CreatUDN(AMGraph &G)//创建图 
{
	printf("请输入顶点和边数:\n");
	cin>>G.vexnum>>G.arcnum;
	 cout<<"请输入顶点:";
	for(int i=0;i<G.vexnum;i++)
	    cin>>G.vex[i];
    for(int i=0;i<G.vexnum;i++)
    {
    	for(int j=0;j<G.vexnum;j++)
    	    G.arcs[i][j]=MaxInt;
	}
	for(int k=0;k<G.arcnum;k++)
	{
		int i,j;
		char v1,v2;
	    int c;
	   	printf("请输入(Vi,Vj)对应的顶点及长度:");
	   	cin>>v1>>v2>>c;                 //输入一条边依附的两个顶点及权值 
	   	Edge[k].Head=v1;
		Edge[k].Tail=v2; 
		Edge[k].lowcost=c;
   	    i = LocateVex(G,v1);  j = LocateVex(G,v2);
        G.arcs[i][j]=G.arcs[j][i]=c;
	}
}
typedef struct Closedge
{
	VerTexType adjvex;//最小边在U中的那个顶点 
	ArcType lowcost;//最小边上的权值 
}closedge[MVNum];
int Min(closedge SZ,AMGraph G)//求出第k个顶点,closedge[k]中存有当前最小边  
{
	int i=0,j,k,min;
	while(!SZ[i].lowcost)
	    i++;
    min=SZ[i].lowcost;
    k=i;
    for(j=i+1;j<G.vexnum;j++)
    {
    	if(SZ[j].lowcost>0)
 	    {
 	    	if(min>SZ[j].lowcost)
 	    	{
 	    		min=SZ[j].lowcost;
 	    		k=j;
			 }
		 }
	}
	return k;
}
void prim(AMGraph G,VerTexType u)//p算法 
{//无向图G以邻接矩阵形式存储,从顶点u出发构造G的最小生成树T,输出T的各条边 
	closedge closedge;
	int k=LocateVex(G,u);//k为顶点u的下标 
	for(int j=0;j<G.vexnum;j++)//对V-U的每一个顶点vj,初始化closedge[j] 
	{
		closedge[j].adjvex=u;
		closedge[j].lowcost=G.arcs[k][j];
	}
	closedge[k].lowcost=0;//初始,U={u} 
	cout<<"最小生成树各边为:"<<endl;
	for(int i=1;i<G.vexnum;i++)
	{//选择其余n-1个顶点,生成n-1条边(n=G.vexnum) 
		k=Min(closedge,G);
		//求出T的下一个结点:第k个顶点,closedge[k]中存有当前最小边 
		cout<<closedge[k].adjvex<<" "<<G.vex[k]<<" "<<closedge[k].lowcost<<endl;
     	closedge[k].lowcost=0;//第k个顶点并入U集 
     	for(int j=0;j<G.vexnum;j++)
     	{
     		if(G.arcs[k][j]<closedge[j].lowcost)//新顶点并入U后重新选择最小边 
   		    {
   		    	closedge[j].adjvex=G.vex[k];
   		    	closedge[j].lowcost=G.arcs[k][j];
            }
		 }
	}
}
int Vexset[MVNum];//辅助数组Vexset的定义 
void kruskal(AMGraph G)//k算法 
{//无向图G以邻接矩阵形式存储,从顶点u出发构造G的最小生成树T,输出T的各条边
	int v1,v2,vs1,vs2;
	for(int i=0;i<G.arcnum;i++){//将Edge[100]中的元素按权值从小到大排序 
	 	for(int j=0;j<G.arcnum-1-i;j++){
	 		if(Edge[j].lowcost>Edge[j+1].lowcost){
	 			Edge[G.arcnum+2]=Edge[j];
	 			Edge[j]=Edge[j+1];
	 			Edge[j+1]=Edge[G.arcnum+2];
			 }
		 }
	 }
	for(int i=0;i<G.vexnum;i++)//辅助数组,表示各顶点自成一个连通分量 
	{
		Vexset[i]=i;
	}
	cout<<"最小生成树各边为:"<<endl;
	for(int i=0;i<G.arcnum;i++)//依次查看数组Edge中的边 
	{
		v1=LocateVex(G,Edge[i].Head);//v1为边的始点Head的下标 
		v2=LocateVex(G,Edge[i].Tail);//v2为边的终点Tail的下标 
		vs1=Vexset[v1];//获取边Edge[i]的始点所在的连通分量vs1 
		vs2=Vexset[v2];//获取边Edge[i]的终点所在的连通分量vs2 
		if(vs1!=vs2)//边的两个顶点分属不同的连通分量 
		{
			cout<<Edge[i].Head<<" "<<Edge[i].Tail<<" "<<Edge[i].lowcost<<endl;//输出此边 
			for(int j=0;j<G.vexnum;j++)//合并vs1和vs2两个分量,即两个统一编号 
			{
				if(Vexset[j]==vs2) Vexset[j]=vs1;//集合编号为vs2的都改为vs1 
			}
		}
	}
}

int main()
{
	AMGraph G;
	CreatUDN(G);
	prim(G,G.vex[0]);
	kruskal(G);
	return 0;
}

 

  • 20
    点赞
  • 190
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值