【PTA数据结构 | C语言版】求最小生成树的Prim算法

本专栏持续输出数据结构题目集,欢迎订阅。

文章目录

题目

请编写程序,实现在带权的无向图中求最小生成树的 Prim 算法。
注意:当多个待收录顶点到当前点集的距离等长时,按编号升序进行收录。

输入格式:
输入首先在第一行给出两个正整数,依次为当前要创建的图的顶点数 n(≤100)和边数 m。
随后 m 行,每行给出一条无向边两端点的编号、权重。顶点编号从 0 开始,权重(≤100)为整数。同行数字均以一个空格分隔。

输出格式:
参考样例。
首先在一行中输出 total weight = x,其中 x 为最小生成树中所有边的总权重。如果最小生成树不存在,则 x 为 −1。
随后在一行中按顶点编号升序输出每个顶点在最小生成树中的父结点的编号。为输出简单起见,每个数字后有一个空格。
注意:此处默认顶点 0 为最小生成树的根结点,其父结点编号规定为 −1。算法初始化时,所有顶点(除了根结点)的父结点编号默认为 0。

输入样例 1:
6 9
0 1 1
0 2 3
1 2 6
1 3 2
2 3 7
2 4 5
2 5 4
3 5 8
4 5 1

输出样例 1:
total weight = 11
-1 0 0 1 5 2

输入样例 2:
7 9
0 1 1
0 2 3
1 2 6
1 3 2
2 3 7
2 4 5
2 5 4
3 5 8
4 5 1

输出样例 2:
total weight = -1
-1 0 0 1 5 2 0

代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_VERTICES 100
#define INF 999999999

int main() {
    int n, m;
    int graph[MAX_VERTICES][MAX_VERTICES];
    int dist[MAX_VERTICES];
    int parent[MAX_VERTICES];
    int visited[MAX_VERTICES];

    // 初始化图
    for (int i = 0; i < MAX_VERTICES; i++) {
        for (int j = 0; j < MAX_VERTICES; j++) {
            graph[i][j] = INF;
        }
    }

    // 读取顶点数和边数
    scanf("%d %d", &n, &m);

    // 读取每条边的信息
    for (int i = 0; i < m; i++) {
        int u, v, weight;
        scanf("%d %d %d", &u, &v, &weight);
        graph[u][v] = weight;
        graph[v][u] = weight;
    }

    // 初始化距离数组和父结点数组
    for (int i = 0; i < n; i++) {
        dist[i] = INF;
        parent[i] = 0;  // 默认父结点为0
        visited[i] = 0;
    }

    // 从顶点0开始
    dist[0] = 0;
    parent[0] = -1;  // 根结点的父结点为-1

    // Prim算法核心
    for (int i = 0; i < n; i++) {
        // 选择距离最小且未被访问的顶点
        int min_dist = INF;
        int u = -1;
        for (int j = 0; j < n; j++) {
            if (!visited[j] && dist[j] < min_dist) {
                min_dist = dist[j];
                u = j;
            } else if (!visited[j] && dist[j] == min_dist && j < u) {
                // 当距离相同时,选择编号较小的顶点
                u = j;
            }
        }

        // 如果找不到符合条件的顶点,说明图不连通
        if (u == -1) {
            break;
        }

        visited[u] = 1;

        // 更新与u相邻的顶点的距离
        for (int v = 0; v < n; v++) {
            if (!visited[v] && graph[u][v] != INF && graph[u][v] < dist[v]) {
                dist[v] = graph[u][v];
                parent[v] = u;
            }
        }
    }

    // 计算总权重并检查是否存在最小生成树
    int total_weight = 0;
    int all_visited = 1;
    for (int i = 0; i < n; i++) {
        if (!visited[i]) {
            all_visited = 0;
            break;
        }
        if (i != 0) {  // 根结点的边不计入总权重
            total_weight += dist[i];
        }
    }

    // 输出结果
    if (all_visited) {
        printf("total weight = %d\n", total_weight);
    } else {
        printf("total weight = -1\n");
    }

    // 输出每个顶点的父结点
    for (int i = 0; i < n; i++) {
        printf("%d ", parent[i]);
    }
    printf("\n");

    return 0;
}
### PTA 6.2 使用Prim算法构建最小生成树 #### 解决方案概述 为了理解如何使用Prim算法来解决PTA 6.2中的最小生成树(MST)问题,先要明白该算法的核心概念。最小生成树是一个连接图中所有顶点而不形成任何环路的子集,并使权重达到最小[^2]。 #### Prim算法流程描述 在执行Prim算法的过程中,会区分两种类型的节点:已加入到正在生长的最小生成树中的白点(即已经处理过的节点),以及尚未被访问的蓝点(未处理的其他节点)。每次迭代时,都会寻找从当前集合V_new出发到达最近的一个新节点之间的最短缘作为下一步扩展的对象[^3]。 #### 实现细节与伪代码展示 下面给出一段Python实现版本的Prim算法用于解给定无向加权连通图G=(V,E)上的MST: ```python import heapq def prim_algorithm(graph, start_vertex): mst = [] visited = {start_vertex} edges = [(cost, start_vertex, to) for to, cost in graph[start_vertex].items()] heapq.heapify(edges) while edges: cost, frm, to = heapq.heappop(edges) if to not in visited: visited.add(to) mst.append((frm, to, cost)) for next_node, weight in graph[to].items(): if next_node not in visited: heapq.heappush(edges, (weight, to, next_node)) return mst ``` 这段代码通过优先队列维护候选列表并不断选取其中代价最低者直至遍历完所有顶点为止。注意这里假设输入`graph`是以邻接表形式表示的一张带权有向图,键为起点而值则是一字典记录着指向终点及其对应的成本信息。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

秋说

感谢打赏

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

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

打赏作者

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

抵扣说明:

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

余额充值