最小生成树问题

[问题描述]

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

[基本要求]

    (1)利用图雷姆或克鲁斯卡尔算法求网的最小生成树;

    (2)以文本形式输出生成树的各条边及其权值。

 [实现提示]

(1)通信线路一旦建立起来一定是双向的,因此构造最小生成树的网一定是无向网;

(2)n个城市间,最多可设置n(n-1)/2条线路;n个城市间建立通信网,只需n-1条线路。问题转化为:如何在可能的线路中选择n-1条,能把所有城市(顶点)均连起来,且总耗费(各边权值之和)最小。

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define INFINITY 99999
#define MAX_VERTEX_NUM 20  //最大顶点个数
typedef int Status;
typedef int InfoType;
typedef char VertexType;
//弧段结点结构
typedef struct ArcNode
{
	int adjvex;               //该弧段所指向的顶点的位置
	struct ArcNode *nextArc;  //指向下一条弧段的指针
	InfoType info;           //该弧段相关信息
} ArcNode;

//顶点表结构
typedef struct VNode
{
	VertexType data;         //图结点的数据类型
	ArcNode *firstarc;      //图结点的头指针,指向依附于该顶点的第一条弧段
}VNode, AdjList[MAX_VERTEX_NUM]; //定义了顶点结点和顶点表类型

								 //图结构
typedef struct
{
	AdjList vertices;     //图的顶点表
	int vexnum, arcnum;    //图的顶点数和弧数
	int kind;             //图的种类标志
}ALGraph;

//边信息-用于最小生成树算法存储边信息
typedef struct
{
	int startnode;
	int endnode;
	InfoType weight;
}Edge;


//用于Prim最小生成树算法
typedef struct
{
	VertexType  adjvex;
	InfoType     lowcost;
} Closedge[MAX_VERTEX_NUM];

Closedge closedge;

Status PrintElement(ALGraph G, int e) {  // 输出元素e的值
	printf("%d ", G.vertices[e].data);  // 实用时,加上格式串
	return OK;
}

//创建图
Status CreateGraph(ALGraph &G);

//销毁图
Status DestroyGraph(ALGraph &G);

//获取顶点位置
int LocateVex(ALGraph G, VertexType u);

//获取v的第一个邻接顶点
int FirstAdjVex(ALGraph G, VertexType v);

//获取返回v的相对于w的下一个邻接顶点
int NextAdjVex(ALGraph G, VertexType v, VertexType w);
//添加新顶点v
Status InsertVex(ALGraph &G, VertexType v);

//删除顶点v
Status DeleteVex(ALGraph &G, VertexType v);

//添加弧段<v,w>
Status InsertArc(ALGraph &G, VertexType v, VertexType w);

//删除弧段<v,w>
Status DeleteArc(ALGraph &G, VertexType v, VertexType w);


Status CreateUDN(ALGraph &G)
{


	int v1, v2, w;
	int i, j, k;
	ArcNode *node = NULL;
	printf("请输入图G的顶点数,边数(空格隔开):\n");
	scanf("%d%d", &G.vexnum, &G.arcnum);
	printf("请输入顶点(整型数,空格隔开):\n");
	for (i = 0; i<G.vexnum; i++)
	{
		scanf("%d", &G.vertices[i].data);
		G.vertices[i].firstarc = NULL;
	}

	for (k = 0; k<G.arcnum; k++)
	{
		printf("请输入%d条弧信息:v1,v2,w(空格隔开)\n", k+1);
		scanf("%d%d%d", &v1, &v2, &w);
		i = LocateVex(G, v1);
		j = LocateVex(G, v2);

		node = (ArcNode*)malloc(sizeof(ArcNode));
		node->adjvex = j;
		node->info = w;
		//头插入法
		node->nextArc = G.vertices[i].firstarc;
		G.vertices[i].firstarc = node;
	}
	return OK;
}//CreateUDN-无向网


 //销毁图
Status DestroyGraph(ALGraph &G)
{
	return OK;
}

//获取顶点位置
int LocateVex(ALGraph G, VertexType u)
{
	int i;
	for (i = 0; i<G.vexnum; i++)
	{
		if (G.vertices[i].data == u)
			return i;
	}
	return -1;
}

//获取v的第一个邻接顶点
int FirstAdjVex(ALGraph G, VertexType v)
{
	ArcNode *p;
	int i;
	i = LocateVex(G, v);
	p = G.vertices[i].firstarc;
	if (p)
		return p->adjvex;
	return -1;
}

//获取返回v的相对于w的下一个邻接顶点
int NextAdjVex(ALGraph G, VertexType v, VertexType w)
{
	ArcNode *p;
	int i;
	i = LocateVex(G, v);
	p = G.vertices[i].firstarc;
	while (p)
	{
		if (G.vertices[p->adjvex].data == w)
		{
			p = p->nextArc;
			if (p) return p->adjvex;
			else return -1;
		}
		p = p->nextArc;
	}
	return -1;
}




void PrintGraph(ALGraph G)
{
	int i;
	ArcNode *p = NULL;
	printf("顶点1(弧尾) 顶点2(弧头) 该该边信息:\n");
	for (i = 0; i<G.vexnum; i++)
	{
		printf("%d", G.vertices[i].data);
		p = G.vertices[i].firstarc;
		while (p)
		{
			printf("--%d    %d ", (p->adjvex) + 1, p->info);
			p = p->nextArc;
		}
		printf("\n");
	}
}

int minimum(ALGraph G, Closedge elosedge)
{
	int i, j;
	int min = INFINITY;
	for (i = 0; i<G.vexnum; i++)
	{
		if (elosedge[i].lowcost>0 && min>elosedge[i].lowcost)
		{
			min = elosedge[i].lowcost;
			j = i;
		}
	}
	return j;
}

//最小生成树——Prim算法
void MiniSpanTree_PRIM(ALGraph G, VertexType u)
{  // 算法7.9
   // 用普里姆算法从第u个顶点出发构造网G的最小生成树T,输出T的各条边。
   // 记录从顶点集U到V-U的代价最小的边的辅助数组定义:
	int i, j, k;
	ArcNode * p;
	k = LocateVex(G, u);
	for (j = 0; j<G.vexnum; ++j)
	{     // 辅助数组初始化
		if (j != k)
		{
			closedge[j].adjvex = u;
			closedge[j].lowcost = INFINITY;
		}
	}
	//右边的距离值
	p = G.vertices[k].firstarc;
	while (p)
	{
		closedge[p->adjvex].lowcost = p->info;
		p = p->nextArc;
	}
	closedge[k].lowcost = 0;      // 初始,U={u}
	for (i = 1; i<G.vexnum; ++i)
	{  // 选择其余G.vexnum-1个顶点
		k = minimum(G, closedge);
		// 求出T的下一个结点:第k顶点
		// 此时closedge[k].lowcost =
		// MIN{ closedge[vi].lowcost | closedge[vi].lowcost>0, vi∈V-U }
		printf("(%d,%d,%d)\n", closedge[k].adjvex, G.vertices[k].data, closedge[k].lowcost);   // 输出生成树的边
		closedge[k].lowcost = 0;    // 第k顶点并入U集
		p = G.vertices[k].firstarc;
		while (p)
		{
			if (p->info>0 && p->info < closedge[p->adjvex].lowcost)
			{
				// 新顶点并入U后重新选择最小边
				// closedge[j] = { G.vexs[k], G.arcs[k][j].adj };
				closedge[p->adjvex].adjvex = G.vertices[k].data;
				closedge[p->adjvex].lowcost = p->info;
			}
			p = p->nextArc;
		}
	}
} // MiniSpanTree

  //判断边数组中是否有端点为i,j的边
Status HasEdge(Edge *edges, int n, int i, int j)
{
	int k;
	for (k = 0; k<n; k++)
	{
		if ((edges[k].endnode == i&&edges[k].startnode == j) || (edges[k].startnode == i&&edges[k].endnode == j))
			return TRUE;
	}
	return FALSE;
}

void main()
{
	//创建图
	ALGraph G;
	int a, b;
	CreateUDN(G);
	printf("\n创建图成功!\n"); PrintGraph(G);
	printf("最小生成树Prim算法:\n");
	printf("输入从哪个顶点开始构建最小生成树:\n");
	scanf("%d", &b);
	MiniSpanTree_PRIM(G, b);
	printf("\n");
}

测试使用的图:

顶点数:6    边数:10

顶点:1,2,3,4,5,6

测试结果:

  • 8
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

DXnima

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

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

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

打赏作者

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

抵扣说明:

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

余额充值