题目描述
现需要在某城市进行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
示例1
输入:3
3
1 2 3 0
1 3 1 0
2 3 5 0
输出:4
说明:只需要在1,2以及2,3基站之间铺设光纤,其成本为3+1=4
示例2
输入:3
1
1 2 5 0
输出:-1
说明:3基站无法与其他基站连接,输出-1
示例3
输入:3
3
1 2 3 0
1 3 1 0
2 3 5 1
输出:1
说明:2,3基站已有光纤相连,只有要再1,3站点之间铺设光纤,其成本为1
解题思路
这个问题可以使用最小生成树(Minimum Spanning Tree)的思想来解决,Kruskal算法是一种常用的实现方式。下面是解题思路:
- 将所有基站之间的光纤连接按照成本从小到大排序,初始化一个并查集(Union-Find)用于记录基站的联通情况。
- 遍历排序后的光纤连接,逐个连接基站,如果连接后不形成环(即两个基站不在同一个集合中),则将它们合并,累加连接的成本。
- 当联通的基站数量达到N-1时,即所有基站都联通,停止连接。
- 如果最终联通的基站数量不等于N-1,说明无法建设成功互联互通的5G网络,输出-1;否则输出累加的连接成本。
题解代码
Python题解代码
class Solution:def findCircleNum(self, isConnected: List[List[int]]) -> int:cities = len(isConnected)visited = set()provinces = 0for i in range(cities):if i not in visited:Q = collections.deque([i])while Q:j = Q.popleft()visited.add(j)for k in range(cities):if isConnected[j][k] == 1 and k not in visited:Q.append(k)provinces += 1return provinces
JAVA题解代码
class Solution {public int findCircleNum(int[][] isConnected) {int ans = 0, n = isConnected.length;boolean[] visit = new boolean[n];for(int i = 0; i < n; ++i){if(!visit[i]){ans++;bfs(i, visit, isConnected);}}return ans;}public void bfs(int i, boolean[] visit, int[][] isConnected){for(int j = 0; j < isConnected.length; ++j){if(isConnected[i][j] == 1 && !visit[j]){visit[j] = true;bfs(j, visit, isConnected);}}}
}
C/C++题解代码
class Solution {
public:int findCircleNum(vector<vector<int>>& isConnected) {int cities = isConnected.size();vector<int> visited(cities);int provinces = 0;queue<int> Q;for (int i = 0; i < cities; i++) {if (!visited[i]) {Q.push(i);while (!Q.empty()) {int j = Q.front(); Q.pop();visited[j] = 1;for (int k = 0; k < cities; k++) {if (isConnected[j][k] == 1 && !visited[k]) {Q.push(k);}}}provinces++;}}return provinces;}
};
JS题解代码
var findCircleNum = function(isConnected) {const cities = isConnected.length;const visited = new Set();let provinces = 0;const queue = new Array();for (let i = 0; i < cities; i++) {if (!visited.has(i)) {queue.push(i);while (queue.length) {const j = queue.shift();visited.add(j);for (let k = 0; k < cities; k++) {if (isConnected[j][k] === 1 && !visited.has(k)) {queue.push(k);}}}provinces++;}}return provinces;
};
代码OJ评判结果
通过测试点
代码讲解
Python题解代码解析:
这段Python代码是用于解决一个图的连通性问题。具体来说,该问题是要求找出城市之间的连通分量个数,其中城市之间的连通关系由isConnected
矩阵表示。
cities
表示城市的总数,即矩阵的行数和列数。visited
是一个集合,用于记录已经访问过的城市。provinces
用于记录连通分量的数量。- 通过遍历城市,对于每个未访问的城市,使用广度优先搜索(BFS)的方式找出与该城市直接或间接相连的所有城市,将它们标记为已访问,并将连通分量数量加一。
最终返回连通分量的数量。
JAVA题解代码解析:
该Java代码与Python代码功能相同,同样是解决城市之间的连通性问题。主要结构和思路如下:
findCircleNum
方法用于返回连通分量的数量。- 使用
boolean
数组visit
记录城市的访问状态。 - 使用
bfs
方法进行广度优先搜索,找出与当前城市直接或间接相连的所有城市,将它们标记为已访问。 - 遍历所有城市,如果某城市未被访问,则进行广度优先搜索,同时将连通分量数量加一。
最终返回连通分量的数量。
C/C++题解代码解析:
这段C++代码与前两段代码实现的功能相同,解决城市之间的连通性问题,使用了BFS算法。
findCircleNum
方法返回连通分量的数量。- 使用
vector<int>
数组visited
记录城市的访问状态。 - 使用
queue<int>
数据结构进行广度优先搜索,找出与当前城市直接或间接相连的所有城市,将它们标记为已访问。 - 遍历所有城市,如果某城市未被访问,则进行广度优先搜索,同时将连通分量数量加一。
最终返回连通分量的数量。
JS题解代码解析:
这段JavaScript代码与前三段代码实现的功能相同,同样是解决城市之间的连通性问题,使用了BFS算法。
findCircleNum
函数返回连通分量的数量。- 使用
Set
对象visited
记录城市的访问状态。 - 使用数组
queue
进行广度优先搜索,找出与当前城市直接或间接相连的所有城市,将它们标记为已访问。 - 遍历所有城市,如果某城市未被访问,则进行广度优先搜索,同时将连通分量数量加一。
最终返回连通分量的数量。
寄语
🚀✨ 朋友,希望你的华为OD机试就像是一场轻松的技术party!愿你的代码如同畅快的音符,跳跃在键盘上,最后弹奏出一曲高分之歌。加油,你是技术舞台上的巨星!通过机试,就像是风轻云淡,轻轻松松就把高分收入囊中。祝愿你的编程之旅一路顺风,破风前行,每一行代码都是成功的注脚!🌈💻