7-2 公路村村通 (30 分) PTA

这篇博客介绍了如何运用Kruskal算法解决最小生成树问题,以实现村落间道路的低成本连通。文章详细阐述了算法的实现过程,并提供了一个C++代码示例,展示了如何对输入数据进行排序和并查集操作,以找到村村通所需的最低成本。此外,还讨论了如何判断数据是否足以保证所有村落都能通过公路连通。
摘要由CSDN通过智能技术生成

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

输入格式:

输入数据包括城镇数目正整数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

分析思路: 

这题其实就是求解最小生成树的问题.这里采用kruskal算法+按秩优化和压缩路径的并查集.

上代码:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class UnionFind {//并查集
public:
    int* root;
    int* rank;
    int count;//用于判断数据是否足够,可以使图连通
    UnionFind(int size)//初始化
    {
        count=size;
        root = new int[size];
        rank = new int[size];
        for (int i = 0;i < size;i++)
        {
            root[i] = i;
            rank[i] = 1;
        }
    }
    int find(int x)//路径压缩
    {
        return root[x] == x ? x : root[x] = find(root[x]);
    }
    void Union(int x, int y)//按秩优化
    {
        count--;//每合并一次就少一个结点,如果村村连通,则应该变成1
        int rootx = find(x), rooty = find(y);
        if (rootx != rooty)
        {
            if (rank[rootx] > rank[rooty])
            {
                root[rooty] = rootx;
            }
            else if (rank[rootx] < rank[rooty])
            {
                root[rootx] = rooty;
            }
            else
            {
                root[rootx] = rooty;
                rank[rooty]++;
            }
        }
    }
    int isConnected(int x, int y)
    {
        return find(x) == find(y);
    }
};
int main()
{
    int n, m;
    int res = 0, cnt = 0;
    cin >> n >> m;
    vector<vector<int>> graph;
    for (int i = 0;i < m;i++)
    {
        vector<int> tmp;
        tmp.resize(3);
        cin >> tmp[0] >> tmp[1] >> tmp[2];
        tmp[0]--;tmp[1]--;//因为题目给的结点编号从1开始,为了对应数组的下标号,减去1
        graph.push_back(tmp);
    }//初始化将村落的数据导入进graph
    sort(begin(graph), end(graph), [](const auto& a, const auto& b)
    {
        return a.back() < b.back();
    });//将graph按权重从小到大排序
    UnionFind uf(n);
    for (const auto& it : graph)
    {
        if (cnt == n - 1) break;//最小生成树最多只可能有n-1条边
        if (uf.isConnected(it[0], it[1])) continue;//判断是否成环
        else
        {
            uf.Union(it[0], it[1]);
            res += it[2];
            cnt++;//记录最小生成树的边数
        }
    }
    if(uf.count!=1)//判断数据是否足够使得村落互通(即图是否连通)
    {
        cout<<-1;
        return 0;
    }
    cout << res;
}

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值