当前位置: 首页 > news >正文

【华为OD】5G网络建设

【华为OD】5G网络建设

题目描述

现需要在某城市进行 5G 网络建设,已经选取 N 个地点设置 5G基站,编号固定为 1 到 N,接下来需要各个基站之间使用光纤进行连接以确保基站能互联互通,不同基站之间架设光纤的成本各不相同,且有些节点之间已经存在光纤相连,请你设计算法,计算出能联通这些基站的最小成本是多少。

注意,基站的联通具有传递性,即基站 A 与基站 B 架设了光纤,基站 B 与基站 C 也架设了光纤,则基站 A 与基站 C 视为可以互相联通。

输入描述

  • 第一行输入表示基站的个数 N,其中 0 < N <= 20
  • 第二行输入表示具备光纤直连条件的基站对的数目 M,其中 0 < M < N*(N - 1) / 2
  • 第三行开始连续输入 M 行数据,格式为 X Y Z P,其中 X Y 表示基站的编号,0 < X <= N,0 < Y <= N 且 X 不等于 Y,Z 表示在 X Y 之间架设光纤的成本,其中 0 < Z < 100,P 表示是否已存在光纤连接,0 表示未连接,1 表示已连接。

输出描述

  • 如果给定条件,可以建设成功互联互通的5G网络,则输出最小的建设成本
  • 如果给定条件,无法建设成功互联互通的5G网络,则输出 -1

示例一

输入:

3
3
1 2 3 0
1 3 1 0
2 3 5 0

输出:

4

说明:
只需要在 1,2 以及 2,3 基站之间铺设光纤,其成本为 3+1=4

示例二

输入:

3
1
1 2 5 0

输出:

-1

说明:
3 基站无法与其他基站连接,输出 -1

示例三

输入:

3
3
1 2 3 0
1 3 1 0
2 3 5 1

输出:

1

说明:
2,3 基站已有光纤相连,只需要再 1,3 站点 2 向铺设,其成本为 1

解题思路

这是一个典型的 最小生成树(MST) 问题。我们需要找到连接所有基站的最小成本。

关键点:

  1. 已经存在的光纤连接(P=1)成本为0,需要建设的光纤连接(P=0)成本为Z
  2. 需要判断是否能够连通所有基站
  3. 如果能连通,求最小生成树的权重和

我将提供两种经典的最小生成树算法:Kruskal算法Prim算法

解法一:Kruskal算法(基于边的贪心算法)

Kruskal算法的核心思想是:

  1. 将所有边按权重排序
  2. 使用并查集维护连通性
  3. 依次选择权重最小且不会形成环的边

Java实现

import java.util.*;public class Solution {static class Edge implements Comparable<Edge> {int u, v, cost;public Edge(int u, int v, int cost) {this.u = u;this.v = v;this.cost = cost;}@Overridepublic int compareTo(Edge other) {return Integer.compare(this.cost, other.cost);}}static class UnionFind {int[] parent, rank;int components;public UnionFind(int n) {parent = new int[n + 1];rank = new int[n + 1];components = n;for (int i = 1; i <= n; i++) {parent[i] = i;}}public int find(int x) {if (parent[x] != x) {parent[x] = find(parent[x]);}return parent[x];}public boolean union(int x, int y) {int px = find(x), py = find(y);if (px == py) return false;if (rank[px] < rank[py]) {parent[px] = py;} else if (rank[px] > rank[py]) {parent[py] = px;} else {parent[py] = px;rank[px]++;}components--;return true;}public boolean isConnected() {return components == 1;}}public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();int m = sc.nextInt();List<Edge> edges = new ArrayList<>();UnionFind uf = new UnionFind(n);for (int i = 0; i < m; i++) {int x = sc.nextInt();int y = sc.nextInt();int z = sc.nextInt();int p = sc.nextInt();int cost = (p == 1) ? 0 : z;edges.add(new Edge(x, y, cost));// 如果已经连接,先在并查集中合并if (p == 1) {uf.union(x, y);}}Collections.sort(edges);int totalCost = 0;for (Edge edge : edges) {if (uf.union(edge.u, edge.v)) {totalCost += edge.cost;}}if (uf.isConnected()) {System.out.println(totalCost);} else {System.out.println(-1);}}
}

Python实现

class UnionFind:def __init__(self, n):self.parent = list(range(n + 1))self.rank = [0] * (n + 1)self.components = ndef find(self, x):if self.parent[x] != x:self.parent[x] = self.find(self.parent[x])return self.parent[x]def union(self, x, y):px, py = self.find(x), self.find(y)if px == py:return Falseif self.rank[px] < self.rank[py]:self.parent[px] = pyelif self.rank[px] > self.rank[py]:self.parent[py] = pxelse:self.parent[py] = pxself.rank[px] += 1self.components -= 1return Truedef is_connected(self):return self.components == 1def solve():n = int(input())m = int(input())edges = []uf = UnionFind(n)for _ in range(m):x, y, z, p = map(int, input().split())cost = 0 if p == 1 else zedges.append((cost, x, y))# 如果已经连接,先在并查集中合并if p == 1:uf.union(x, y)edges.sort()total_cost = 0for cost, u, v in edges:if uf.union(u, v):total_cost += costif uf.is_connected():print(total_cost)else:print(-1)solve()

C++实现

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;struct Edge {int u, v, cost;bool operator<(const Edge& other) const {return cost < other.cost;}
};class UnionFind {
public:vector<int> parent, rank;int components;UnionFind(int n) : parent(n + 1), rank(n + 1, 0), components(n) {for (int i = 1; i <= n; i++) {parent[i] = i;}}int find(int x) {if (parent[x] != x) {parent[x] = find(parent[x]);}return parent[x];}bool unite(int x, int y) {int px = find(x), py = find(y);if (px == py) return false;if (rank[px] < rank[py]) {parent[px] = py;} else if (rank[px] > rank[py]) {parent[py] = px;} else {parent[py] = px;rank[px]++;}components--;return true;}bool isConnected() {return components == 1;}
};int main() {int n, m;cin >> n >> m;vector<Edge> edges;UnionFind uf(n);for (int i = 0; i < m; i++) {int x, y, z, p;cin >> x >> y >> z >> p;int cost = (p == 1) ? 0 : z;edges.push_back({x, y, cost});// 如果已经连接,先在并查集中合并if (p == 1) {uf.unite(x, y);}}sort(edges.begin(), edges.end());int totalCost = 0;for (const Edge& edge : edges) {if (uf.unite(edge.u, edge.v)) {totalCost += edge.cost;}}if (uf.isConnected()) {cout << totalCost << endl;} else {cout << -1 << endl;}return 0;
}

解法二:Prim算法(基于顶点的贪心算法)

Prim算法的核心思想是:

  1. 从任意顶点开始
  2. 每次选择连接已访问顶点和未访问顶点的最小权重边
  3. 直到所有顶点都被访问

Java实现

import java.util.*;public class Solution2 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();int m = sc.nextInt();// 构建邻接表List<List<int[]>> graph = new ArrayList<>();for (int i = 0; i <= n; i++) {graph.add(new ArrayList<>());}// 并查集处理已连接的边UnionFind uf = new UnionFind(n);for (int i = 0; i < m; i++) {int x = sc.nextInt();int y = sc.nextInt();int z = sc.nextInt();int p = sc.nextInt();int cost = (p == 1) ? 0 : z;graph.get(x).add(new int[]{y, cost});graph.get(y).add(new int[]{x, cost});if (p == 1) {uf.union(x, y);}}// 使用Prim算法boolean[] visited = new boolean[n + 1];PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[1] - b[1]);// 从节点1开始visited[1] = true;for (int[] edge : graph.get(1)) {pq.offer(new int[]{edge[0], edge[1]});}int totalCost = 0;int edgesUsed = 0;while (!pq.isEmpty() && edgesUsed < n - 1) {int[] current = pq.poll();int node = current[0];int cost = current[1];if (visited[node]) continue;visited[node] = true;totalCost += cost;edgesUsed++;for (int[] edge : graph.get(node)) {if (!visited[edge[0]]) {pq.offer(new int[]{edge[0], edge[1]});}}}// 检查是否所有节点都被访问boolean allConnected = true;for (int i = 1; i <= n; i++) {if (!visited[i]) {allConnected = false;break;}}if (allConnected) {System.out.println(totalCost);} else {System.out.println(-1);}}static class UnionFind {int[] parent, rank;public UnionFind(int n) {parent = new int[n + 1];rank = new int[n + 1];for (int i = 1; i <= n; i++) {parent[i] = i;}}public int find(int x) {if (parent[x] != x) {parent[x] = find(parent[x]);}return parent[x];}public boolean union(int x, int y) {int px = find(x), py = find(y);if (px == py) return false;if (rank[px] < rank[py]) {parent[px] = py;} else if (rank[px] > rank[py]) {parent[py] = px;} else {parent[py] = px;rank[px]++;}return true;}}
}

Python实现

import heapq
from collections import defaultdictdef solve_prim():n = int(input())m = int(input())# 构建邻接表graph = defaultdict(list)for _ in range(m):x, y, z, p = map(int, input().split())cost = 0 if p == 1 else zgraph[x].append((y, cost))graph[y].append((x, cost))# 使用Prim算法visited = [False] * (n + 1)min_heap = []# 从节点1开始visited[1] = Truefor neighbor, cost in graph[1]:heapq.heappush(min_heap, (cost, neighbor))total_cost = 0edges_used = 0while min_heap and edges_used < n - 1:cost, node = heapq.heappop(min_heap)if visited[node]:continuevisited[node] = Truetotal_cost += costedges_used += 1for neighbor, edge_cost in graph[node]:if not visited[neighbor]:heapq.heappush(min_heap, (edge_cost, neighbor))# 检查是否所有节点都被访问all_connected = all(visited[i] for i in range(1, n + 1))if all_connected:print(total_cost)else:print(-1)solve_prim()

C++实现

#include <iostream>
#include <vector>
#include <queue>
#include <climits>
using namespace std;int main() {int n, m;cin >> n >> m;// 构建邻接表vector<vector<pair<int, int>>> graph(n + 1);for (int i = 0; i < m; i++) {int x, y, z, p;cin >> x >> y >> z >> p;int cost = (p == 1) ? 0 : z;graph[x].push_back({y, cost});graph[y].push_back({x, cost});}// 使用Prim算法vector<bool> visited(n + 1, false);priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;// 从节点1开始visited[1] = true;for (auto& edge : graph[1]) {pq.push({edge.second, edge.first});}int totalCost = 0;int edgesUsed = 0;while (!pq.empty() && edgesUsed < n - 1) {auto current = pq.top();pq.pop();int cost = current.first;int node = current.second;if (visited[node]) continue;visited[node] = true;totalCost += cost;edgesUsed++;for (auto& edge : graph[node]) {if (!visited[edge.first]) {pq.push({edge.second, edge.first});}}}// 检查是否所有节点都被访问bool allConnected = true;for (int i = 1; i <= n; i++) {if (!visited[i]) {allConnected = false;break;}}if (allConnected) {cout << totalCost << endl;} else {cout << -1 << endl;}return 0;
}

算法复杂度分析

Kruskal算法:

  • 时间复杂度:O(M log M),主要是排序的复杂度
  • 空间复杂度:O(N + M)

Prim算法:

  • 时间复杂度:O(M log N),使用优先队列的复杂度
  • 空间复杂度:O(N + M)

总结

两种算法都能有效解决这个5G网络建设问题:

  1. Kruskal算法更适合边数较少的稀疏图,实现相对简单
  2. Prim算法更适合边数较多的稠密图,在节点数较少时表现更好

对于这道题目,由于N ≤ 20,两种算法的性能差异不大,都能很好地解决问题。关键是要正确处理已存在的光纤连接(成本为0)和判断图的连通性。


文章转载自:

http://OZrkDCl1.jtdrz.cn
http://0JfGKlBX.jtdrz.cn
http://jGdbVBSI.jtdrz.cn
http://sRmOKwEm.jtdrz.cn
http://Gex7rMPy.jtdrz.cn
http://wUAJ7Ruw.jtdrz.cn
http://n5eumXvg.jtdrz.cn
http://MXJ32QSz.jtdrz.cn
http://d6cf6XRZ.jtdrz.cn
http://oGxXMAvW.jtdrz.cn
http://u3TPfqBz.jtdrz.cn
http://a2MCaqRd.jtdrz.cn
http://GTY9nUh8.jtdrz.cn
http://sQKirUXE.jtdrz.cn
http://wpRzu6HG.jtdrz.cn
http://2YjFeY7w.jtdrz.cn
http://e2pAFYtv.jtdrz.cn
http://DPgZJY4X.jtdrz.cn
http://Dm7fKwtd.jtdrz.cn
http://omtBluLG.jtdrz.cn
http://OCZu7KlQ.jtdrz.cn
http://F0v5kykT.jtdrz.cn
http://lILIDpEd.jtdrz.cn
http://FCephQNa.jtdrz.cn
http://GZuSSEMa.jtdrz.cn
http://MExcpRxU.jtdrz.cn
http://rKckEVKB.jtdrz.cn
http://ws3j5Tpy.jtdrz.cn
http://cmaHjtg1.jtdrz.cn
http://nRJnERWX.jtdrz.cn
http://www.dtcms.com/a/374937.html

相关文章:

  • 使用LLM(Ollama部署)为Bertopic确定的主题命名
  • C++容器:list
  • PAT 1178 File Path
  • ESP32开发:ubuntu22.04 下esp-idf开发环境搭建
  • JWT全面理解
  • C++:类和对象
  • Linux(3)|入门的开始:Linux基本指令(3)
  • REST接口幂等设计深度解析
  • 在Word和WPS文字中便捷切换英文段落大小写
  • 【华为OD】寻找连续区间
  • 渗透测试信息收集步骤与工具详解
  • #C语言——刷题攻略:牛客编程入门训练(十):攻克 循环控制(二),轻松拿捏!
  • 乐吾乐大屏可视化组态软件【SQL数据源】
  • 打工人日报#20250909
  • PyTorch中的flatten操作详解:从start_dim=1说起
  • 上网行为审计软件应该如何选择?适配图书馆管理的上网行为审计软件推荐
  • 计算机网络第五章(1)——传输层(概念 + UDP)
  • AI 时代,我们是否应该重温极限编程?
  • Protobuf 新版“调试表示为什么有链接?为什么会打码?我该怎么改代码?
  • php 使用html 生成pdf word wkhtmltopdf 系列1
  • vcsa6.0 升级6.7
  • python中的深拷贝与浅拷贝详细介绍
  • 【Java】Hibernate二级缓存下
  • R 包的管理涉及两个概念:二进制包的下载缓存位置和包的最终安装位置。你看到的临时路径只是包的下载缓存,它并不会长期占用C盘空间
  • Android 项目:画图白板APP开发(四)——笔锋(单 Path)
  • Nginx反向代理与负载均衡部署
  • 微算法科技(NASDAQ: MLGO)采用量子相位估计(QPE)方法,增强量子神经网络训练
  • Vue: Class 与 Style 绑定
  • 在 Cursor IDE 中配置 SQLTools 连接 MySQL 数据库指南(Windows 11)
  • SKYTRAC-无人机、无人机系统和城市空中交通卫星通信 – BVLOS 和 C2 卫星通信终端和任务服务器