牛客题解 | 寻宝
1.牛客题解 | 寻宝
2.牛客题解 | 寻找Coder3.牛客题解 | 寻找丑数4.牛客题解 | 寻找合法字符串5.牛客题解 | 寻找奇数6.牛客题解 | 寻找子串7.牛客题解 | 将满二叉树转换为求和树8.牛客题解 | 小A最多会新认识的多少人9.牛客题解 | 小Q的排序10.牛客题解 | 小东分苹果11.牛客题解 | 小招喵跑步12.牛客题解 | 小明卖食物13.牛客题解 | 小明的字符串14.牛客题解 | 小易喜欢的单词15.牛客题解 | 小易喜欢的数列16.牛客题解 | 小易的字典17.牛客题解 | 小游戏18.牛客题解 | 小熊吃糖19.牛客题解 | 小球的距离20.牛客题解 | 小米Git21.牛客题解 | 小米大礼包22.牛客题解 | 山寨金闪闪23.牛客题解 | 工作方案24.牛客题解 | 左右最值最大差25.牛客题解 | 带权的DAG节点排序26.牛客题解 | 平均年龄27.牛客题解 | 平方串28.牛客题解 | 年会抢玩偶游戏29.牛客题解 | 年终奖30.牛客题解 | 幸运子序列31.牛客题解 | 幸运数32.牛客题解 | 幸运数字33.牛客题解 | 幸运的袋子34.牛客题解 | 幼儿园分班35.牛客题解 | 序列合并36.牛客题解 | 序列找数37.牛客题解 | 序列操作38.牛客题解 | 序列模式匹配39.牛客题解 | 建物流中转站40.牛客题解 | 异或41.牛客题解 | 彩色宝石项链42.牛客题解 | 彩色的砖块43.牛客题解 | 彩色的砖块_144.牛客题解 | 循环数比较45.牛客题解 | 循环数比较_146.牛客题解 | 微信红包47.牛客题解 | 怪数48.牛客题解 | 懂二进制49.牛客题解 | 手串50.牛客题解 | 手套51.牛客题解 | 手机号52.牛客题解 | 扎金花53.牛客题解 | 扑克牌四则运算54.牛客题解 | 打印二维数组55.牛客题解 | 打印回形数56.牛客题解 | 扭蛋机57.牛客题解 | 找“异数”58.牛客题解 | 找出单向链表中的一个节点,该节点到尾指针的距离为K59.牛客题解 | 找出重复的数字60.牛客题解 | 找到最近的NPC61.牛客题解 | 找缺失数字62.牛客题解 | 找零63.牛客题解 | 折纸问题64.牛客题解 | 抛小球65.牛客题解 | 抽牌66.牛客题解 | 拍照队形67.牛客题解 | 拓扑结构相同子树68.牛客题解 | 招聘会小礼品69.牛客题解 | 拜访70.牛客题解 | 括号匹配方案71.牛客题解 | 括号匹配深度72.牛客题解 | 括号配对问题73.牛客题解 | 拼凑三角形74.牛客题解 | 拼凑正方形75.牛客题解 | 拼凑硬币76.牛客题解 | 拼凑面额77.牛客题解 | 挑选镇长78.牛客题解 | 换乘79.牛客题解 | 换零钱80.牛客题解 | 排序81.牛客题解 | 排序次数82.牛客题解 | 提取优惠券码83.牛客题解 | 搬圆桌84.牛客题解 | 搭积木85.牛客题解 | 操作序列86.牛客题解 | 操作序列_187.牛客题解 | 改考卷88.牛客题解 | 数三角形89.牛客题解 | 数位重排90.牛客题解 | 数列91.牛客题解 | 数列的和92.牛客题解 | 数列计算93.牛客题解 | 数列还原94.牛客题解 | 数字和为sum的方法数95.牛客题解 | 数字字符96.牛客题解 | 数字序列97.牛客题解 | 数字构造98.牛客题解 | 数字游戏99.牛客题解 | 数字游戏_1100.牛客题解 | 数字的情绪题目
解题思路
这是一个最小生成树问题,需要找到连接所有空地的最小生成树,并且要求最长的边最小。这种问题可以使用Kruskal算法的变体来解决。
关键点:
- 使用Kruskal算法构建最小生成树
- 按照边的长度排序
- 使用并查集维护连通性
- 找到满足条件的最小最大边
算法步骤:
- 对所有边按长度排序
- 使用二分查找最小的最大边长度
- 检查是否能连通所有点
- 返回满足条件的最小值
代码
#include <bits/stdc++.h>
using namespace std;
class UnionFind {
private:
vector<int> parent;
vector<int> rank;
int count;
public:
UnionFind(int n) : parent(n), rank(n, 0), count(n) {
for (int i = 0; i < n; i++) {
parent[i] = i;
}
}
int find(int x) {
if (parent[x] != x) {
parent[x] = find(parent[x]);
}
return parent[x];
}
void unite(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY) {
if (rank[rootX] < rank[rootY]) {
swap(rootX, rootY);
}
parent[rootY] = rootX;
if (rank[rootX] == rank[rootY]) {
rank[rootX]++;
}
count--;
}
}
bool isConnected(int x, int y) {
return find(x) == find(y);
}
int getCount() {
return count;
}
};
class Solution {
public:
int findMinMaxEdge(int n, vector<vector<int>>& edges) {
// 按边长排序
sort(edges.begin(), edges.end(),
[](const vector<int>& a, const vector<int>& b) {
return a[2] < b[2];
});
int left = 0, right = edges.back()[2];
int result = right;
while (left <= right) {
int mid = left + (right - left) / 2;
// 检查是否能用不超过mid长度的边连通所有点
if (canConnect(n, edges, mid)) {
result = mid;
right = mid - 1;
} else {
left = mid + 1;
}
}
return result;
}
private:
bool canConnect(int n, const vector<vector<int>>& edges, int maxLen) {
UnionFind uf(n + 1);
// 只使用长度不超过maxLen的边
for (const auto& edge : edges) {
if (edge[2] > maxLen) break;
uf.unite(edge[0], edge[1]);
}
// 检查是否所有点都连通(除了0)
int root = uf.find(1);
for (int i = 2; i <= n; i++) {
if (uf.find(i) != root) return false;
}
return true;
}
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector<vector<int>> edges(m, vector<int>(3));
for (int i = 0; i < m; i++) {
cin >> edges[i][0] >> edges[i][1] >> edges[i][2];
}
Solution solution;
cout << solution.findMinMaxEdge(n, edges) << endl;
return 0;
}
import java.util.*;
class UnionFind {
private int[] parent;
private int[] rank;
private int count;
public UnionFind(int n) {
parent = new int[n];
rank = new int[n];
count = n;
for (int i = 0; i < n; i++) {
parent[i] = i;
}
}
public int find(int x) {
if (parent[x] != x) {
parent[x] = find(parent[x]);
}
return parent[x];
}
public void unite(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY) {
if (rank[rootX] < rank[rootY]) {
int temp = rootX;
rootX = rootY;
rootY = temp;
}
parent[rootY] = rootX;
if (rank[rootX] == rank[rootY]) {
rank[rootX]++;
}
count--;
}
}
public boolean isConnected(int x, int y) {
return find(x) == find(y);
}
public int getCount() {
return count;
}
}
class Solution {
private boolean canConnect(int n, int[][] edges, int maxLen) {
UnionFind uf = new UnionFind(n + 1);
// 只使用长度不超过maxLen的边
for (int[] edge : edges) {
if (edge[2] > maxLen) break;
uf.unite(edge[0], edge[1]);
}
// 检查是否所有点都连通
int root = uf.find(1);
for (int i = 2; i <= n; i++) {
if (uf.find(i) != root) return false;
}
return true;
}
public int findMinMaxEdge(int n, int[][] edges) {
// 按边长排序
Arrays.sort(edges, (a, b) -> Integer.compare(a[2], b[2]));
int left = 0, right = edges[edges.length - 1][2];
int result = right;
while (left <= right) {
int mid = left + (right - left) / 2;
if (canConnect(n, edges, mid)) {
result = mid;
right = mid - 1;
} else {
left = mid + 1;
}
}
return result;
}
}
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int[][] edges = new int[m][3];
for (int i = 0; i < m; i++) {
edges[i][0] = sc.nextInt();
edges[i][1] = sc.nextInt();
edges[i][2] = sc.nextInt();
}
Solution solution = new Solution();
System.out.println(solution.findMinMaxEdge(n, edges));
sc.close();
}
}
class UnionFind:
def __init__(self, n):
self.parent = list(range(n))
self.rank = [0] * n
self.count = n
def find(self, x):
if self.parent[x] != x:
self.parent[x] = self.find(self.parent[x])
return self.parent[x]
def unite(self, x, y):
root_x = self.find(x)
root_y = self.find(y)
if root_x != root_y:
if self.rank[root_x] < self.rank[root_y]:
root_x, root_y = root_y, root_x
self.parent[root_y] = root_x
if self.rank[root_x] == self.rank[root_y]:
self.rank[root_x] += 1
self.count -= 1
def is_connected(self, x, y):
return self.find(x) == self.find(y)
def get_count(self):
return self.count
class Solution:
def can_connect(self, n: int, edges: list, max_len: int) -> bool:
uf = UnionFind(n + 1)
# 只使用长度不超过max_len的边
for edge in edges:
if edge[2] > max_len:
break
uf.unite(edge[0], edge[1])
# 检查是否所有点都连通
root = uf.find(1)
return all(uf.find(i) == root for i in range(2, n + 1))
def find_min_max_edge(self, n: int, edges: list) -> int:
# 按边长排序
edges.sort(key=lambda x: x[2])
left, right = 0, edges[-1][2]
result = right
while left <= right:
mid = left + (right - left) // 2
if self.can_connect(n, edges, mid):
result = mid
right = mid - 1
else:
left = mid + 1
return result
def main():
n, m = map(int, input().split())
edges = []
for _ in range(m):
p, q, k = map(int, input().split())
edges.append([p, q, k])
solution = Solution()
print(solution.find_min_max_edge(n, edges))
if __name__ == "__main__":
main()
算法及复杂度
- 算法:Kruskal算法 + 二分查找
- 时间复杂度:,其中 是边数, 是最大边长
- 空间复杂度:,用于并查集数据结构
合集:
牛客笔试大厂真题题解3
分类:
牛客笔试大厂真题题解3
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】