PTA 公路村村通
- 一、前导
- 1. 需要掌握的知识
- 2. 题目信息
- 二、解题思路分析
- 1. 题意理解
- 1. 1 输入数据
- 1.2 输出数据
- 2. 思路分析(重点)
- 三、具体实现
- 1. 弯路和bug
- 2. 代码框架(重点)
- 2.1 采用的数据结构
- 2.2 程序主体框架
- 2.3 各分支函数
- 3. 完整编码
一、前导
1. 需要掌握的知识
- 最小生成树,Prim算法
二、解题思路分析
1. 题意理解
- 最小生成树问题
1. 1 输入数据
6 15 //城镇数目6个(图顶点)、候选道路数目15个(边)
1 2 5 //城镇编号、城镇编号、道路改建成本
1 3 3
4 5 10
4 6 8
5 6 3
1.2 输出数据
- 输出公路村村通需要的最低成本,即打印最小生成树的权重;若不存在MST,打印-1
2. 思路分析(重点)
- 最小生成树问题,可以用Prim算法解决,由于题目仅要求输出最小生成树的权重,并未要求打印最小生成树,对Prim算法进行适当调整即可AC
三、具体实现
1. 弯路和bug
- 按照Prim算法(避环法)实现即可
2. 代码框架(重点)
2.1 采用的数据结构
- 使用二维数组存储图:使用空间换解题时间,代码量会少很多
#define max 1001 //城市从1开始编号,最大值为1000
int Graph[max][max]; //方便起见 使用全局变量
int VertexNumber,EdgeNumber;
- 数组dist 和 parent配合Prim算法使用
int dist[max]; //dist数组表示顶点到MST的距离,0表示在MST中
int parent[max];//存储顶点的父结点
2.2 程序主体框架
程序伪码描述
int main()
{
1.构建图
2.执行Prim算法
return 0;
}
2.3 各分支函数
- 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;
}
- 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. 完整编码
- 本文如果对你有帮助,请点赞鼓励 ,谢谢 😊
- 如有建议或意见,欢迎留言
#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;
}