数据结构 _ 基础练习 _ 7-10 公路村村通

原题

点此链接1

题目分析

可参考课本(高等教育出版社 - 陈越 - 《数据结构》)P225中关于prim算法的描述解题。
本题相对于课本描述的算法来说,不需要考虑 父节点 (parent),只需要考虑一个总的WPL就行。

代码

/**
 * @file Road Connect Every Village.cpp
 * @author your name (you@domain.com)
 * @brief 公路村村通 : https://pintia.cn/problem-sets/15/problems/718
 * @version 0.1
 * @date 2021-02-06
 * 
 * @copyright Copyright (c) 2021
 * 
 */

#include <algorithm>
#include <iostream>
#include <map>
#include <vector>
#include <queue>
#include <cmath>

using namespace std;

const int intMax = pow(2, 15) - 1;

/*
 * 解题思路:
 * prim 算法描述
 *  基本变量
 *  1. 路径点集合:
 *      点 - 特殊值(初始为最大值),采用带索引的向量集
 *          点表示当前索引
 *          特殊值:
 *              无穷 表示从未访问过的点;
 *              0  表示树内点;
 *              >0 表示当前点距离树的距离
 *  2. 最终费用:只需要计算一个费用和就行!
 *  (3.父节点)
 * 
 * 初始化
 * v0 特殊值应为 0
 * 对v0的每一个邻接点,需要初始化路径点集合中的特殊值为 到v0 的 路经长
 * (更新父节点为v0)
 * 
 * while(路径集合中找不到符合要求的路径了)
 * {
 *  选择 路径集合 中 具有 最小路径的 点 A
 *  确定A点收入 收集点集 中
 *  对点A的每一个邻接点
 *      选择树外点B
 *          如果 点A到B的距离 小于 点B到树的距离
 *              更新 B到树的距离
 *              (更新B的父结点)
 * }
 * 判断是否找到了每一个点以输出
 */

int main()
{
    int v, e;
    cin >> v >> e;
    vector<vector<pair<int, int>>> data(v);

    for (auto i = 0; i < e; i++)
    {
        int p1, p2, cost;
        cin >> p1 >> p2 >> cost;
        // @warning 减去1 保证0号是有效的
        // 这道题不需要考虑城镇号,所以其他地方不需要再作进一步考虑了
        data[p1 - 1].push_back({p2 - 1, cost});
        data[p2 - 1].push_back({p1 - 1, cost});
    }

    vector<int> dis(v, intMax); // 路经长

    auto MinIndex = [&dis, v]() -> int {
        auto index = -1;
        auto min = intMax;
        for (auto i = 0; i < v; i++)
            if (dis[i] < min && dis[i])
            {
                index = i;
                min = dis[i];
            }
        return index;
    };

    // 从 0 开始
    auto sum = 0;
    dis[0] = 0;
    for (auto &r : data[0])
        dis[r.first] = r.second;
    while (true)
    {
        // 选择距树最短的那个点
        auto minIndex = MinIndex();
        if (minIndex == -1)
            break;
        sum += dis[minIndex];
        dis[minIndex] = 0;

        // 对每一个邻接点
        for (auto &r : data[minIndex])
            // 对每一个树外点
            if (dis[r.first] && dis[r.first] > r.second)
                dis[r.first] = r.second;
    }
    if (count_if(dis.begin(), dis.end(), [](int in) { return !in; }) != v)
        cout << -1 << endl;
    else
        cout << sum << endl;

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值