PTA 08-图7 公路村村通(30 分)
题目描述:
现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本。
输入格式:
输入数据包括城镇数目正整数N(≤1000)和候选道路数目M(≤3N);随后的M行对应M条道路,每行给出3个正整数,分别是该条道路直接连通的两个城镇的编号以及该道路改建的预算成本。为简单起见,城镇从1到N编号。输出格式:
输出村村通需要的最低成本。如果输入数据不足以保证畅通,则输出−1,表示需要建设更多公路。
解题方法:
这题可以用Prim算法生成最小生成树,通过判断最终最小生成树的结点个数是否为顶点个数(即边数为顶点个数-1),如果是,则可以生成最小生成树,能够做到村村通,如果不是,则不行。
由于这里的公路编号从1开始,因此我在初始化领接矩阵的时候也是选择从下标1开始赋值,方便后续操作。
程序:
#include <stdio.h>
#include <stdlib.h>
#define MaxVertexNum 1003
#define INFINITY 65536
int MGraph[MaxVertexNum][MaxVertexNum];
int dist[MaxVertexNum] = {INFINITY};
int parent[MaxVertexNum] = {0}; /* 如果需要输出联通路径,这里不需要,可无视 */
int FindMinDist(int Nv)
{ /* 寻找未被收录的当前最短路径的顶点下标 */
int MinDist = INFINITY, V, Min;
for (V = 1; V <= Nv; V++)
{
if (dist[V] != 0 && dist[V] < MinDist)
{ /* 如果节点V未被收录(为0表示被收录)并且小于最短距离 */
MinDist = dist[V]; // 更新最短距离
Min = V; // 设置V的父亲结点为0
}
}
if (MinDist < INFINITY)
return Min; // 如果找到返回顶点下标
else
return 0;
}
int Prim(int Nv)
{
int TotalCost = 0, Vcount = 0, V, W;
for (V = 1; V <= Nv; V++)
{ /* 初始化dist,并设置所有结点的父节点为1 */
dist[V] = MGraph[1][V];
parent[V] = 1;
}
/* 把1点收入 */
dist[1] = 0;
parent[1] = -1;
Vcount++;
while (1)
{
V = FindMinDist(Nv);
if (!V)
break;
Vcount++;
TotalCost += dist[V];
dist[V] = 0; // 把V点收录进来
for (W = 1; W <= Nv; W++)
{
if (dist[W] != 0 && MGraph[V][W] < dist[W])
{ /* 如果W未被收录 并且V<->W之间的距离变小 */
dist[W] = MGraph[V][W];
parent[W] = V;
}
}
}
if (Vcount == Nv) // 如果最小生成树的边数正好为Nv-1
return TotalCost;
else // 反之,无法构成最小生成树
return -1;
}
int main(int argc, char const *argv[])
{
int N, M, v, w, cost, MinCost;
scanf("%d %d", &N, &M);
/* 初始化图 */
for (int i = 1; i <= N; i++)
for (int j = 1; j <= N; j++)
MGraph[i][j] = INFINITY;
/* 输入图信息并更新图 */
for (int i = 1; i <= M; i++)
{
scanf("%d %d %d", &v, &w, &cost);
MGraph[v][w] = cost;
MGraph[w][v] = cost;
}
MinCost = Prim(N);
printf("%d\n", MinCost); // 输出结果
return 0;
}