PTA 公路村村通 思路分析及代码解析

一、前导

1. 需要掌握的知识

  1. 最小生成树Prim算法

2. 题目信息

  1. 题目来源:PTA / 拼题A
  2. 题目地址:公路村村通

二、解题思路分析

1. 题意理解

  1. 最小生成树问题

1. 1 输入数据

6 15   //城镇数目6个(图顶点)、候选道路数目15个(边)
1 2 5 //城镇编号、城镇编号、道路改建成本
1 3 3
4 5 10
4 6 8
5 6 3

1.2 输出数据

  1. 输出公路村村通需要的最低成本,即打印最小生成树的权重;若不存在MST,打印-1

2. 思路分析(重点)

  1. 最小生成树问题,可以用Prim算法解决,由于题目仅要求输出最小生成树的权重,并未要求打印最小生成树,对Prim算法进行适当调整即可AC

三、具体实现

1. 弯路和bug

  1. 按照Prim算法(避环法)实现即可

2. 代码框架(重点)

2.1 采用的数据结构

  1. 使用二维数组存储图:使用空间换解题时间,代码量会少很多
#define max 1001 //城市从1开始编号,最大值为1000
int Graph[max][max]; //方便起见 使用全局变量
int VertexNumber,EdgeNumber;
  1. 数组dist 和 parent配合Prim算法使用
int dist[max]; //dist数组表示顶点到MST的距离,0表示在MST中
int parent[max];//存储顶点的父结点

2.2 程序主体框架

               程序伪码描述
int main()
{	
	1.构建图
	2.执行Prim算法
	return 0;
}

2.3 各分支函数

  1. FindDistMin( ):找到dist数组中的最小值 且 该顶点未被收录到MST中
#define Null -1
#define maxWeight 99999
typedef int vertex; 
vertex FindDistMin()
{
	vertex V=Null;
	int distMin=maxWeight;
	
	for(int i=1;i<=VertexNumber;i++)
	{
		if(dist[i] && distMin>dist[i]) 
		{ // dist[i]=0 表示顶点i已收录进MST中
			distMin=dist[i];
			V=i;
		}
	}
	return V;
}
  1. Prim() :本题AC的核心函数。首先复习下Prim算法的步骤,由于本题仅需要计算MST的权值,因此不涉及MST的创建(包括边的插入),因此只需要使用Prim算法中的非边部分就可以AC本题
    在这里插入图片描述
void Prim() //本题只要最小生成树权值,不需要建立MST 
{
	vertex V,W;
	int vertexCount=0; //记录MST中的顶点数量,当MST中的顶点数 等于 图的顶点数时,MST才存在
	int MSTWeight=0; //记录MST的权值
	 
	for(V=1;V<=VertexNumber;V++) //向 dist parent 两个数组赋初值 
	{
		parent[V]=Source;
		dist[V]=maxWeight; 
	}	
		
	dist[Source]=0; //首先将源点1收入MST
	vertexCount++;
	parent[Source]=-1; //最先收入的顶点为MST的树根
	
	for(V=1;V<=VertexNumber;V++)
	{  //收入一个顶点进MST,更新其邻接点的dist值
		if(Graph[Source][V])
			dist[V]=Graph[Source][V];
	}

	while(true)
	{
		V=FindDistMin();
		if(V==Null) break; //所有顶点都已经收入MST 或 图不连通
		dist[V]=0; //按Prim算法,将dist最小的顶点收入MST
		vertexCount++;
		MSTWeight += Graph[parent[V]][V]; //累计MST权重
		//将边加入MST的编码省略(边的两个端点 [parent[V]]  [V]) 
		
		for(W=1;W<=VertexNumber;W++) //更新V的邻接点W的dist值
		{
			if(dist[W]!=0 && Graph[V][W]!=0) //dist[W]!=0 说明还未收录入MST 
			{
				if(Graph[V][W]<dist[W]) 
				{
					dist[W]=Graph[V][W];
					parent[W]=V;
				}
			} 
		}
		 
	}
	if(vertexCount!=VertexNumber)
		cout<<Null;
	else cout<<MSTWeight;
	return;
}

3. 完整编码

  1. 本文如果对你有帮助,请点赞鼓励 ,谢谢 😊
  2. 如有建议或意见,欢迎留言
#include <cstdlib>
#include <iostream>
using namespace std;

#define max 1001 //城市从1开始编号,最大值为1000 
#define Null -1
#define maxWeight 99999
#define Source 1 
typedef int vertex; 

int Graph[max][max]; //方便起见 使用全局变量
int VertexNumber,EdgeNumber;
int dist[max]; //dist数组表示顶点到MST的距离,0表示在MST中
int parent[max];//存储顶点的父结点

void createGraph();
void Prim(); 
vertex FindDistMin();
int main()
{
	createGraph();
	Prim();
	
	return 0;
}

void Prim() //本题只要最小生成树权值,不需要建立MST 
{
	vertex V,W;
	int vertexCount=0; //记录MST中的顶点数量,当MST中的顶点数 等于 图的顶点数时,MST才存在
	int MSTWeight=0; //记录MST的权值
	 
	for(V=1;V<=VertexNumber;V++) //向 dist parent 两个数组赋初值 
	{
		parent[V]=Source;
		dist[V]=maxWeight; 
	}	
		
	dist[Source]=0; //首先将源点1收入MST
	vertexCount++;
	parent[Source]=-1; //最先收入的顶点为MST的树根
	
	for(V=1;V<=VertexNumber;V++)
	{  //收入一个顶点进MST,更新其邻接点的dist值
		if(Graph[Source][V])
			dist[V]=Graph[Source][V];
	}

	while(true)
	{
		V=FindDistMin();
		if(V==Null) break; //所有顶点都已经收入MST 或 图不连通
		dist[V]=0; //按Prim算法,将dist最小的顶点收入MST
		vertexCount++;
		MSTWeight += Graph[parent[V]][V]; //累计MST权重
		//将边加入MST的编码省略(边的两个端点 [parent[V]]  [V]) 
		
		for(W=1;W<=VertexNumber;W++) //更新V的邻接点W的dist值
		{
			if(dist[W]!=0 && Graph[V][W]!=0) //dist[W]!=0 说明还未收录入MST 
			{
				if(Graph[V][W]<dist[W]) 
				{
					dist[W]=Graph[V][W];
					parent[W]=V;
				}
			} 
		}
		 
	}
	if(vertexCount!=VertexNumber)
		cout<<Null;
	else cout<<MSTWeight;
	return;
}

vertex FindDistMin()
{
	vertex V=Null;
	int distMin=maxWeight;
	
	for(int i=1;i<=VertexNumber;i++)
	{
		if(dist[i] && distMin>dist[i])
		{
			distMin=dist[i];
			V=i;
		}
	}
	return V;
}

void createGraph()
{
	
	vertex V1,V2,Weight;
	
	cin>>VertexNumber>>EdgeNumber;
	
	for(int i=1;i<=VertexNumber;i++) //图顶点从1开始编号
	{
		
		for(int j=1;j<=VertexNumber;j++)
		{
			Graph[i][j]=0;
		} 
	} 
	
	for(int k=1;k<=EdgeNumber;k++)
	{
		cin>>V1>>V2>>Weight;
		Graph[V1][V2]=Weight;
		Graph[V2][V1]=Weight;
	}
	return;
}

四、参考

  1. 浙江大学 陈越、何钦铭老师主讲的数据结构
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值