华为OD机试 - 英雄联盟 - 动态规划(Python/JS/C/C++ 2024 D卷 200分)

在这里插入图片描述

华为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)。具体思路如下:

  1. 问题转换:
    • 将 10 名参与者分成两队,每队 5 人,即将 10 个数分成两个子集,每个子集的元素个数都是 5,且这两个子集的和的差值尽量小。
    • 我们可以将这个问题转化为求两个子集的和尽量接近总和的一半。
  2. 动态规划:
    • 使用动态规划数组 dp 来记录可以达到的某个和。dp[i] 表示是否可以通过从前 i 个评分中选出若干个数,使得它们的和为 i。
    • 我们需要找到最接近总和的一半的子集和。
  3. 实现步骤:
    • 计算所有评分的总和 sum。
    • 初始化 dp 数组,长度为 sum/2 + 1,dp[0] 初始化为 true。
    • 通过评分数组更新 dp 数组。
    • 找到最接近 sum/2 的子集和 subset_sum。
    • 计算两队的实力差 diff = sum - 2 * subset_sum。
  4. 复杂度:
    • 时间复杂度: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在线答疑。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哪 吒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值