OD C卷 - 5G网络建设

5G网络建设 (200)

  • 选取n个地点建设5G基站,地点编号1 -> n;
  • 各个基站之间使用光纤连接,设计算法计算连通所有基站的最小成本;
  • 基站的连通具有传递性,A->B连通,B->C连通,则A->C连通;
    输入描述:
    第一行输入基站个数n, 0< n <=20;
    第二行输入已具备光纤连接的基站对数m;
    第三行开始的m行,格式为 X Y Z P,X Y表示基站编号 1-n且不相等,Z表示XY之间的光纤成本(0, 100),P表示是否已存在光纤连接,0未连接,1已连接;
    输出描述:
    输出最小的建设成本(所有基站连通),无法建设完成输出-1;

示例1

输入:

3

3

1 2 3 0

1 3 1 0

2 3 5 0

输出:

4

说明:只需在1、2及2、3之间建设光纤

示例2

输入:

3

1

1 2 5 0

输出:

-1

示例3

输入:

3

3

1 2 3 0

1 3 1 0

2 3 5 1

输出:

1

思路:

  • 并查集,实现图连通;
  • 并查集是一种高级数据结构,实现不相交集合的合并问题;
  • 步骤:
    • 初始化,每个节点的父(根)节点是自己;
    • find查找,查找每个节点的父节点,如果父节点是自己则返回自己,否则递归查找其父节点的父节点,将最终的父节点(即父为自己的节点)赋值作为前一个节点的父节点,并返回;
    • 合并,两个节点的父节点不一样,则合并,即其中一个节点所在集合的父节点->的父节点设置为另一个节点所在集合的父节点;
  • 本题思路:
    • 已连接的,只需合并,edges_num += 1;
    • 未连接的需要按照成本升序排序,然后依次建立连接,同时edges_num += 1 and total_cost += cur_cost;
    • edges_num == n - 1 则连通,否则无法连通;
python 复制代码
class UF: # 并查集
    def __init__(self, n): # 1 初始化
        # 每个节点的父节点是自己
        self.fa = [i for i in range(n + 1)]
        self.edges = 0 # n个节点 n-1条边可以连通

    def find(self, x): # 2 查询节点的根
        # 当前节点的根,根为自己则return
        if x == self.fa[x]:
            return x
        # 否则 递归查询根 (路径压缩)
        self.fa[x] = self.find(self.fa[x])
        return self.fa[x]

    def union(self, x, y): # 3 合并,两个集合的根不同,则合并
        self.fa[self.find(x)] = self.find(y)
        self.edges += 1 # 边数+1

    def get_edges(self):
        return self.edges


n = int(input())  # 总节点数
m = int(input())  # 连接数对
uf = UF(n)
networks = []

for i in range(m): # m行
    data = [int(x) for x in input().strip().split()]

    if data[-1] == 1:
        # 已建立连接,使用并查集 进行合并(边+1 不计成本)
        if uf.find(data[0]) != uf.find(data[1]): # 根节点不同 则合并
            uf.union(data[0], data[1])
    else:
        # 尚未建立连接
        networks.append([data[0], data[1], data[2]]) # 成本即权重

# 按照成本 升序排序
networks = sorted(networks, key=lambda x: x[2])

total_cost = 0 # 成本
i = 0 # networks 列表索引
while True:
    if i >= len(networks):
        break
    else:
        # 对于尚未连接的基站,进行并查集 合并, 成本累加起来
        if uf.find(networks[i][0]) != uf.find(networks[i][1]): # 根节点不同,则合并
            # 不相交集合  的合并
            uf.union(networks[i][0], networks[i][1])
            # 成本累加
            total_cost += networks[i][2]

        # 连接的边数
        if uf.get_edges() == n - 1:  # n个节点 只需n-1条边 连通
            break
    # 继续合并第二组
    i += 1

if uf.get_edges() != n - 1:
    total_cost = -1

print(total_cost)
相关推荐
Unstoppable226 天前
代码随想录算法训练营第 56 天 | 拓扑排序精讲、Dijkstra(朴素版)精讲
java·数据结构·算法·
Unstoppable227 天前
代码随想录算法训练营第 55 天 | 53. 寻宝(Prim + Kruskal)
数据结构·算法··kruskal·prim
_OP_CHEN8 天前
【算法基础篇】(二十四)数据结构之并查集拓展:从 “单一关系” 到 “复杂约束”,这篇带你解锁进阶玩法!
数据结构·蓝桥杯·并查集·算法竞赛·acm/icpc·带权并查集·扩展域并查集
_OP_CHEN10 天前
【算法基础篇】(二十三)数据结构之并查集基础:从原理到实战,一篇吃透!
数据结构·算法·蓝桥杯·并查集·算法竞赛·acm/icpc·双亲表示法
Dream it possible!13 天前
LeetCode 面试经典 150_图_克隆图(90_133_C++_中等)(深度优先:DFS)
c++·leetcode·面试·
让我们一起加油好吗22 天前
【数据结构】带权并查集
数据结构·c++·算法·并查集·带权并查集
月半流苏1 个月前
Problem: lab-week10-exercise02 Building a Fiber Network
c++·算法·并查集
让我们一起加油好吗1 个月前
【数据结构】并查集(操作详解 + 模板 + 练习)
数据结构·算法·并查集·洛谷
奔跑吧邓邓子1 个月前
【C语言实战(71)】C语言进阶:树与图的奇妙数据之旅
c语言···开发实战
2401_841495642 个月前
【数据结构】基于Floyd算法的最短路径求解
java·数据结构·c++·python·算法··floyd