2025华为暑期机试题目100+200+300*20%
第一题 补丁版本
某测试工具升级时总选择迭代次数最多的补丁版本,已知这些补丁版本的前序版本(即依赖该版本修改发布新补丁版本),前序版本的个数<=1,且不会存在互为前序版本的情况。请给出最终可以升级的补丁版本。版本号只包含大写字母和数字。
输入:第一行为记录的版本迭代关系个数N,范围是[1,100000];第二行到第N+1行:每行包含两个字符串,第一个字符串为当前版本,第二个字符串为前序版本,用空格隔开。字符串包含字符个数为[1,100],没有前序版本的第二个字符串固定为NA。
6
CN0010 BF0001
BF0001 AZ0001
AZ0001 NA
BF0010 AZ0001
AW0001 NA
BF0011 AZ0001
输出
CN0010
具体代码
#include <iostream>
#include <unordered_map>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
int main() {
int n;
cin >> n;
unordered_map<string, vector<string>> graph; // 前序 -> 当前
unordered_map<string, int> in_degree; // 入度
unordered_map<string, int> depth; // 版本的迭代次数
unordered_map<string, bool> exist; // 所有出现过的版本
for (int i = 0; i < n; ++i) {
string cur, pre;
cin >> cur >> pre;
exist[cur] = true;
if (pre != "NA") {
graph[pre].push_back(cur);
in_degree[cur]++;
exist[pre] = true;
} else {
// 确保NA情况也初始化
if (!in_degree.count(cur)) in_degree[cur] = 0;
}
}
// 拓扑排序
queue<string> q;
for (auto &p : exist) {
if (in_degree[p.first] == 0) {
q.push(p.first);
depth[p.first] = 0; // 根节点迭代次数为0
}
}
while (!q.empty()) {
string node = q.front();
q.pop();
for (string &next : graph[node]) {
depth[next] = max(depth[next], depth[node] + 1);
in_degree[next]--;
if (in_degree[next] == 0) {
q.push(next);
}
}
}
// 找最大深度
int max_depth = 0;
for (auto &p : depth) {
max_depth = max(max_depth, p.second);
}
// 收集所有最大深度版本
vector<string> result;
for (auto &p : depth) {
if (p.second == max_depth) {
result.push_back(p.first);
}
}
sort(result.begin(), result.end());
for (int i = 0; i < result.size(); ++i) {
if (i > 0) cout << " ";
cout << result[i];
}
cout << endl;
return 0;
}
解决思路:
处理输入构建图,处理每条路的依赖关系。然后用拓扑排序计算深度,将所有入度为0的节点加入队列,取出节点在遍历其后继节点,然后更新后继的深度为当前节点深度+1与已有最大值深度的较高者。减少后继的入度,假如为0就加入队列。最后遍历所有版本,找到最大值,根据最大值找到其对应版本。排序后输出。
第二题 地铁耗时最短的线路
大湾区某城市地铁线路非常密集,乘客很难一眼看出选择哪条线路乘型比较合适,为了解决这个问题,地铁公司希望你开发一个程序帮助乘客挑选合适的乘坐线路,使得乘坐时间最短,地铁公司可以提供的数据是各相邻站点之间的乘坐时间。
输入
第一行:N,站点总数,3<=N<=20.第二行:乘客的出发和到达站点。第三行起:相邻站点之间的乘坐时间,每对站点一行,站点名称是单个小写字母,站点名一定包括出发和到达站点,输入保证只有一个唯一解;结束行:0000
12
a e
a b 2
b c 2
c d 2
d e 2
f b 3
b g 3
g h 2
h i 3
j h 2
h e 3
e k 2
k l 4
0000
输出
a b c d e
blog.csdnimg.cn/direct/4e2e0b5862514d44be632034a7bc9fa2.jpeg)
具体代码
#include <iostream>
#include <unordered_map>
#include <vector>
#include <string>
#include <queue>
#include <climits>
#include <stack>
using namespace std;
struct Edge {
string to;
int time;
};
int main() {
int N;
cin >> N;
string start, end;
cin >> start >> end;
unordered_map<string, vector<Edge>> graph;
string u, v;
int t;
while (cin >> u) {
if (u == "0000") break;
cin >> v >> t;
graph[u].push_back({v, t});
graph[v].push_back({u, t}); // 双向图
}
// Dijkstra
unordered_map<string, int> dist;
unordered_map<string, string> prev;
for (auto &p : graph) {
dist[p.first] = INT_MAX;
}
dist[start] = 0;
auto cmp = [&](const pair<int, string>& a, const pair<int, string>& b) {
return a.first > b.first;
};
priority_queue<pair<int, string>, vector<pair<int, string>>, decltype(cmp)> pq(cmp);
pq.push({0, start});
while (!pq.empty()) {
auto [d, cur] = pq.top(); pq.pop();
if (d > dist[cur]) continue;
for (auto &edge : graph[cur]) {
int new_dist = d + edge.time;
if (new_dist < dist[edge.to]) {
dist[edge.to] = new_dist;
prev[edge.to] = cur;
pq.push({new_dist, edge.to});
}
}
}
// 输出路径
vector<string> path;
string curr = end;
while (curr != start) {
path.push_back(curr);
curr = prev[curr];
}
path.push_back(start);
reverse(path.begin(), path.end());
for (int i = 0; i < path.size(); ++i) {
if (i > 0) cout << " ";
cout << path[i];
}
cout << endl;
return 0;
}
解决思路:
首先根据输入读取节点站和每条边的权重来构建无向图,再使用迪杰斯特拉算法求最短路径,最后再由终点回溯回起点,反转结果再输出。
迪杰斯特拉算法具体实现过程:首先初始化所有距离为无穷大,初始距离为0,在利用优先队列构建最小堆,初始节点入队。进入主循环,获取当前距离最小节点,如果已经处理过就跳过,遍历所有邻接边,更新距离再入队。
第三题 最小操作次数
给定一个的二维矩阵NN,其中包含[1,N^2]的互不相同的正整数。定义一种操作:每次可以选择矩阵中的一个元素,将其与其在顺时针螺旋顺序中的下一个元素交换位置例如: 在33的矩阵中,螺旋顺序为从左上角[0,0]开始,向右到[0,2],向下到[2,2],向左到[2,0],再向上到[1,0],最后到中心[1,1]。目标是通过若干次操作,将矩阵变为“顺时针螺旋递增”顺序,即螺旋遍历时元素依次为1,2,3,4…N^2。求将给定矩阵转换为顺时针螺旋递增顺序所需的最小操作次数。
输入
2
3 1
2 4
输出
3
具体代码
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
const int MOD = 1e9 + 7;
// 螺旋顺序展开
vector<int> spiralOrder(const vector<vector<int>>& matrix, int N) {
vector<int> spiral;
int top = 0, bottom = N - 1, left = 0, right = N - 1;
while (top <= bottom && left <= right) {
for (int j = left; j <= right; j++) spiral.push_back(matrix[top][j]);
top++;
for (int i = top; i <= bottom; i++) spiral.push_back(matrix[i][right]);
right--;
if (top <= bottom)
for (int j = right; j >= left; j--) spiral.push_back(matrix[bottom][j]);
bottom--;
if (left <= right)
for (int i = bottom; i >= top; i--) spiral.push_back(matrix[i][left]);
left++;
}
return spiral;
}
// 求最小交换次数(基于置换环)
int minSpiralSwaps(const vector<int>& spiral) {
int n = spiral.size();
// 构造 target 值到索引的映射(目标是1~n递增)
vector<int> pos(n); // pos[i] 表示 spiral[i] 在目标数组中应该在的位置
for (int i = 0; i < n; ++i) {
pos[i] = spiral[i] - 1; // 值为1~n,对应目标下标0~n-1
}
vector<bool> visited(n, false);
long long swaps = 0;
for (int i = 0; i < n; ++i) {
if (visited[i] || pos[i] == i)
continue;
int cycle_len = 0;
int j = i;
while (!visited[j]) {
visited[j] = true;
j = pos[j];
cycle_len++;
}
swaps = (swaps + cycle_len - 1) % MOD;
}
return swaps;
}
int main() {
int N;
cin >> N;
vector<vector<int>> matrix(N, vector<int>(N));
for (int i = 0; i < N; ++i)
for (int j = 0; j < N; ++j)
cin >> matrix[i][j];
vector<int> spiral = spiralOrder(matrix, N);
int result = minSpiralSwaps(spiral);
cout << result << endl;
return 0;
}
解决思路:
首先螺旋展开数组,再利用置换环计算交换次数。