华为OD机试 2024E卷题库疯狂收录中,刷题点这里
专栏导读
本专栏收录于《华为OD机试真题(Python/JS/C/C++)》。
刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。
一、题目描述
部门准备举办一场王者荣耀表演赛,有 10 名游戏爱好者参与,分为两队,每队 5 人。
每位参与者都有一个评分,代表着他的游戏水平。
为了表演赛尽可能精彩,我们需要把 10 名参赛者分为实力尽量相近的两队。一队的实力可以表示为这一队 5 名队员的评分总和。
现在给你 10 名参与者的游戏水平评分,请你根据上述要求分队最后输出这两组的实力差绝对值。
例: 10 名参赛者的评分分别为 5 1 8 3 4 6 7 10 9 2,分组为 (1 3 5 8 10) (2 4 6 7 9),两组实力差最小,差值为 1。有多种分法,但实力差的绝对值最小为 1。
二、输入描述
10 个整数,表示 10 名参与者的游戏水平评分。范围在[1,10000]之间
三、输出描述
1 个整数,表示分组后两组实力差绝对值的最小值。
四、测试用例
1、输入
1 2 3 4 5 6 7 8 9 10
2、输出
1
3、说明
10 名队员分成两组,两组实力差绝对值最小为 1。
五、解题思路
要解决这个问题,我们可以使用经典的动态规划(Dynamic Programming)中的子集和问题(Subset Sum Problem)。具体思路如下:
- 问题转换:
- 将 10 名参与者分成两队,每队 5 人,即将 10 个数分成两个子集,每个子集的元素个数都是 5,且这两个子集的和的差值尽量小。
- 我们可以将这个问题转化为求两个子集的和尽量接近总和的一半。
- 动态规划:
- 使用动态规划数组 dp 来记录可以达到的某个和。dp[i] 表示是否可以通过从前 i 个评分中选出若干个数,使得它们的和为 i。
- 我们需要找到最接近总和的一半的子集和。
- 实现步骤:
- 计算所有评分的总和 sum。
- 初始化 dp 数组,长度为 sum/2 + 1,dp[0] 初始化为 true。
- 通过评分数组更新 dp 数组。
- 找到最接近 sum/2 的子集和 subset_sum。
- 计算两队的实力差 diff = sum - 2 * subset_sum。
- 复杂度:
- 时间复杂度:O(n * sum/2),其中 n 是评分个数,sum/2 是评分总和的一半。
- 空间复杂度:O(sum/2)。
六、Python算法源码
def main():
scores = []
for _ in range(10):
scores.append(int(input()))
print(minimum_difference(scores))
def minimum_difference(scores):
total_sum = sum(scores)
target = total_sum // 2
dp = [False] * (target + 1)
dp[0] = True
# 动态规划更新 dp 数组
for score in scores:
for j in range(target, score - 1, -1):
dp[j] = dp[j] or dp[j - score]
# 找到最接近 target 的子集和
subset_sum = 0
for i in range(target, -1, -1):
if dp[i]:
subset_sum = i
break
# 计算两组实力差的绝对值
return abs(total_sum - 2 * subset_sum)
if __name__ == "__main__":
main()
七、JavaScript算法源码
function main() {
const scores = [];
for (let i = 0; i < 10; i++) {
scores.push(parseInt(prompt("Enter a score: "), 10));
}
console.log(minimumDifference(scores));
}
function minimumDifference(scores) {
const totalSum = scores.reduce((acc, score) => acc + score, 0);
const target = Math.floor(totalSum / 2);
const dp = new Array(target + 1).fill(false);
dp[0] = true;
// 动态规划更新 dp 数组
for (let score of scores) {
for (let j = target; j >= score; j--) {
dp[j] = dp[j] || dp[j - score];
}
}
// 找到最接近 target 的子集和
let subsetSum = 0;
for (let i = target; i >= 0; i--) {
if (dp[i]) {
subsetSum = i;
break;
}
}
// 计算两组实力差的绝对值
return Math.abs(totalSum - 2 * subsetSum);
}
main();
八、C算法源码
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int minimumDifference(int* scores, int size) {
int totalSum = 0;
for (int i = 0; i < size; i++) {
totalSum += scores[i];
}
int target = totalSum / 2;
int* dp = (int*)calloc(target + 1, sizeof(int));
dp[0] = 1;
// 动态规划更新 dp 数组
for (int i = 0; i < size; i++) {
for (int j = target; j >= scores[i]; j--) {
dp[j] = dp[j] || dp[j - scores[i]];
}
}
// 找到最接近 target 的子集和
int subsetSum = 0;
for (int i = target; i >= 0; i--) {
if (dp[i]) {
subsetSum = i;
break;
}
}
free(dp);
// 计算两组实力差的绝对值
return abs(totalSum - 2 * subsetSum);
}
int main() {
int scores[10];
for (int i = 0; i < 10; i++) {
scanf("%d", &scores[i]);
}
int result = minimumDifference(scores, 10);
printf("%d\n", result);
return 0;
}
九、C++算法源码
#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
int minimumDifference(vector<int>& scores) {
int totalSum = accumulate(scores.begin(), scores.end(), 0);
int target = totalSum / 2;
vector<bool> dp(target + 1, false);
dp[0] = true;
// 动态规划更新 dp 数组
for (int score : scores) {
for (int j = target; j >= score; j--) {
dp[j] = dp[j] || dp[j - score];
}
}
// 找到最接近 target 的子集和
int subsetSum = 0;
for (int i = target; i >= 0; i--) {
if (dp[i]) {
subsetSum = i;
break;
}
}
// 计算两组实力差的绝对值
return abs(totalSum - 2 * subsetSum);
}
int main() {
vector<int> scores(10);
for (int i = 0; i < 10; i++) {
cin >> scores[i];
}
int result = minimumDifference(scores);
cout << result << endl;
return 0;
}
🏆下一篇:华为OD机试真题 - 简易内存池(Python/JS/C/C++ 2024 E卷 200分)
🏆本文收录于,华为OD机试真题(Python/JS/C/C++)
刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。