PTA数据结构-08-图7 公路村村通

本文详细解析了Kruskal算法解决最小生成树问题的实现过程,通过实例展示了如何利用最小堆和并查集处理村落间道路建设的成本优化问题。

一、题目

现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本。

输入格式:

输入数据包括城镇数目正整数N(≤1000)和候选道路数目M(≤3N);随后的M行对应M条道路,每行给出3个正整数,分别是该条道路直接连通的两个城镇的编号以及该道路改建的预算成本。为简单起见,城镇从1到N编号。

输出格式:

输出村村通需要的最低成本。如果输入数据不足以保证畅通,则输出−1,表示需要建设更多公路。

输入样例:

6 15
1 2 5
1 3 3
1 4 7
1 5 4
1 6 2
2 3 4
2 4 6
2 5 2
2 6 6
3 4 6
3 5 1
3 6 1
4 5 10
4 6 8
5 6 3

输出样例:

12

二、解答

import java.util.*;
//Kruskal:最小堆 + 并查集
public class Main{
    static Road[] minHeap = new Road[3001];
    static int index = 0;
    public static void main(String[] args) {
        //获取数据
        Scanner sc = new Scanner(System.in);
        int cityNum = sc.nextInt();
        int roadNum = sc.nextInt();
        minHeap[0] = new Road(0,0, 0); //设置哨兵
        for (int i = 0; i < roadNum; i++) { inHeap(new Road(sc.nextInt(), sc.nextInt(), sc.nextInt()));}
        sc.close();
        //处理过程  Kruskal   并查集
        int[] coll = new int[cityNum+1];
        int count = 0;
        int lenSum = 0;
        for (int i = 0; i < roadNum; i++) {
            if (count == cityNum - 1) break;
            Road curRoad = outHeap();
            if (collRoad(curRoad, coll)){
                count++;
                lenSum += curRoad.len;
            }
        }
        //输出结果
        int negInt = 0;
        for (int i = 1; i < cityNum+1; i++) { if (coll[i] <= 0) negInt++;}
        if (negInt != 1) lenSum = -1;
        System.out.println(lenSum);
    }
    public static boolean collRoad(Road road, int[] coll){
        if (coll[road.a] == 0 && coll[road.b] == 0) {
            coll[road.a] = -2;
            coll[road.b] = road.a;
            return true;
        }
        if (coll[road.a] == 0) {
            int root = findRoot(road.b, coll);
            coll[road.a] = root;
            coll[root]--;
            return true;
        }
        if (coll[road.b] == 0) {
            int root = findRoot(road.a, coll);
            coll[road.b] = root;
            coll[root]--;
            return true;
        }
        int roota = findRoot(road.a, coll), rootb = findRoot(road.b,coll);
        if (roota == rootb) return false;  //抛弃这条路,否则构成回路
        if (roota < rootb) {  // a集大,b集小
            coll[roota] += coll[rootb];
            coll[rootb] = roota;
        } else {
            coll[rootb] += coll[roota];
            coll[roota] = rootb;
        }
        return true;
    }
    public static int findRoot(int num, int[] coll){
        if (coll[num] == 0) return 0;
        while(coll[num] > 0) num = coll[num];
        return num;
    }
    public static void inHeap(Road road){
        minHeap[++index] = road;
        int temp = index;
        while(minHeap[temp].len < minHeap[temp/2].len){
            Road tempRoad = minHeap[temp/2];
            minHeap[temp/2] = minHeap[temp];
            minHeap[temp] = tempRoad;
            temp /= 2;
        }
    }
    public static Road outHeap(){
        if (index <= 0) return null;
        Road res = minHeap[1];
        minHeap[1] = minHeap[index--];
        int temp = 1;
        while (temp * 2 <= index) {
            if (temp * 2 == index) {
                if (minHeap[temp*2].len < minHeap[temp].len) {
                    Road tempRoad = minHeap[temp * 2];
                    minHeap[temp * 2] = minHeap[temp];
                    minHeap[temp] = tempRoad;
                }
                break;
            } else {
                int min = temp*2+1;
                if (minHeap[temp*2].len < minHeap[temp*2+1].len) min = temp*2;
                if (minHeap[min].len < minHeap[temp].len) {
                    Road tempRoad = minHeap[min];
                    minHeap[min] = minHeap[temp];
                    minHeap[temp] = tempRoad;
                    temp = min;
                } else break;
            }
        }
        return res;
    }
}
class Road{
    int a = 0;
    int b = 0;
    int len = 0;
    public Road(int a, int b, int len){
        this.a = a;
        this.b = b;
        this.len = len;
    }
}

思路:

  1. 什么类型的题?很明显是最小生成树
  2. 如何存放数据?创建Road类
  3. 最小生成树的实现?Prim和Kruskal
  4. 本题实现:RoadNum < 3CityNum 稀疏图   使用Kruskal:最小堆+并查集

思考:

Prim的实现

 

 

### PTA 数据结构与算法 题目集 7-51 解析 #### 题目概述 题目编号为7-51的数据结构与算法练习题通常涉及较为复杂的逻辑运算以及特定的数据处理方法。这类题目旨在考察学生对于高级数据结构的理解程度及其应用能力。 #### 主要知识点覆盖 该类题目往往聚焦于但不限于以下几个方面: - **论**:特别是关于连通性和最优化路径的选择问题[^1]。 - **动态规划**:解决具有重叠子问题特性的计算难题,提高效率的同时减少冗余计算。 - **贪心算法**:针对某些可以逐步构建最优解的情况适用此策略来简化解过程。 #### 示例解答思路(假设) 考虑到具体题目细节未给出,这里提供一种基于上述领域内常见模式的通用解决方案框架: 当面对一个涉及到多个节点关系的问题时,可以通过建立加权无向模型来进行分析。利用邻接矩阵或者边列示法存储这些连接信息,并采用Prim或Kruskal算法寻找最小生树(MST)。这不仅能够有效地降低整体成本,而且有助于理解整个系统的拓扑特征。 ```cpp // 假设使用C++编写并实现了Kruskal算法找到给定形中的MST #include <iostream> #include <vector> using namespace std; struct Edge { int src, dest, weight; }; class Graph { public: vector<Edge> edges; int V, E; void addEdge(int u, int v, int w); int find(vector<int>& parent, int i); void Union(vector<int>& parent, int x, int y); void KruskalMST(); }; void Graph::addEdge(int u, int v, int w) { edges.push_back({u, v, w}); } int Graph::find(vector<int>& parent, int i) { if (parent[i] == -1) return i; return find(parent, parent[i]); } void Graph::Union(vector<int>& parent, int x, int y) { int xset = find(parent, x); int yset = find(parent, y); parent[xset] = yset; } void Graph::KruskalMST() { // 实现Kruskal算法的具体逻辑... } ``` 请注意以上代码仅为示意性质,在实际编程环境中需根据具体的业务需调整函数定义及内部实现。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值