当前位置: 首页 > article >正文

【华为OD-E卷-MVP争夺战 100分(python、java、c++、js、c)】

【华为OD-E卷-MVP争夺战 100分(python、java、c++、js、c)】

题目

在星球争霸篮球赛对抗赛中,最大的宇宙战队希望每个人都能拿到MVP,MVP的条件是单场最高分得分获得者。
可以并列所以宇宙战队决定在比赛中尽可能让更多队员上场,并且让所有得分的选手得分都相同,
然而比赛过程中的每1分钟的得分都只能由某一个人包揽

输入描述

  • 输入第一行为一个数字 t ,表示为有得分的分钟数

1 ≤ t ≤ 50 第二行为 t 个数字,代表每一分钟的得分 p,

1 ≤ p ≤ 50

输出描述

  • 输出有得分的队员都是MVP时,最少得MVP得分

用例

用例一:
输入:
9
5 2 1 5 2 1 5 2 1
输出:
6

python解法

  • 解题思路:
  • 本问题的目标是将球员的得分分成若干队伍(最多 t 个队伍),并使得每个队伍的得分尽可能接近。最终返回的是每个队伍的最大可能得分。

具体思路:

计算总得分:
首先计算所有球员的总得分。
最大分配值的二分查找:
假设每个队伍可以获得的最大得分为 total // count。
检查是否能够将球员分配到 count 个队伍,使每队得分恰好为 total // count。
分组问题的递归回溯:
通过回溯算法尝试将球员分配到 count 个队伍中。
每个队伍的得分不超过目标值 goal。
若所有球员成功分配,返回 True;否则,尝试减少队伍数量并重新分配。
关键点:

利用递归回溯解决分组问题。
通过逐步减少队伍数量,找到最优的最大得分分配方案。

class TeamMVP:
    def __init__(self, points):
        # 初始化球员得分列表
        self.points = points

    def calc_mvp(self, count):
        # 计算总得分
        total = sum(self.points)

        # 从最多 count 个队伍开始尝试,逐步减少队伍数量
        while count > 0:
            # 检查是否可以分成 count 个队伍,目标每队得分为 total // count
            if self.divide_teams(total // count, count):
                return total // count
            count -= 1

        # 如果无法分组,返回总得分
        return total

    def divide_teams(self, goal, players):
        # 检查是否可以分成 players 个队伍且每队得分为 goal
        if sum(self.points) % players != 0 or goal < max(self.points):
            return False

        # 初始化每个队伍的当前得分
        buckets = [0] * players
        # 将球员得分从高到低排序
        self.points.sort(reverse=True)

        def backtrack(idx):
            # 如果所有球员都成功分配,返回 True
            if idx == len(self.points):
                return True

            for j in range(players):
                # 跳过重复的队伍分配,避免重复计算
                if j > 0 and buckets[j] == buckets[j - 1]:
                    continue

                # 如果当前球员可以加入队伍 j 且不超过目标值
                if buckets[j] + self.points[idx] <= goal:
                    buckets[j] += self.points[idx]  # 加入队伍 j
                    # 递归分配下一个球员
                    if backtrack(idx + 1):
                        return True
                    buckets[j] -= self.points[idx]  # 回溯,移除当前球员

            return False

        return backtrack(0)

if __name__ == "__main__":
    # 输入队伍数量和球员得分
    t = int(input())
    scores = list(map(int, input().split()))
    # 创建 MVP 计算器对象
    mvp_calculator = TeamMVP(scores)
    # 输出每队最大可能得分
    print(mvp_calculator.calc_mvp(t))

java解法

  • 解题思路
  • 本问题的目标是将分数 scores 分成最多 t 个队伍,并使得每个队伍的得分尽可能相等。要求输出每队的最大可能得分。

具体思路:

总分计算与排序:
首先计算总分 total 并对分数从高到低排序,方便在回溯时优先分配高分。
逐步尝试减少队伍数:
从最多 t 个队伍开始尝试,将总分均分到 t 个队伍中。
如果不能满足,减少队伍数 t 并重新尝试。
检查分配可能性:
目标分数为 total / t,每队必须恰好达到目标分数。
检查是否可以通过回溯算法将分数分配到 t 个队伍中,使每队总分为 targetScore。
回溯分配:
使用递归回溯分配分数,尝试将每个分数放入某个队伍中。
剪枝优化:
如果当前分数无法放入队伍(超过目标值),则跳过。
如果两个队伍当前得分相同,则跳过重复尝试。

import java.util.Scanner;
import java.util.ArrayList;
import java.util.Collections;

public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        // 读取输入:队伍数量和分数
        int t = input.nextInt();
        ArrayList<Integer> scores = new ArrayList<>();
        for (int i = 0; i < t; i++) {
            scores.add(input.nextInt());
        }
        // 计算并输出每队的最大可能得分
        System.out.println(calculateMVPScore(scores, t));
    }

    // 计算每队最大可能的得分
    public static int calculateMVPScore(ArrayList<Integer> scores, int t) {
        // 对分数降序排序
        Collections.sort(scores, Collections.reverseOrder());

        // 计算总得分
        int total = scores.stream().mapToInt(Integer::intValue).sum();

        // 从最多 t 个队伍开始尝试,逐步减少队伍数量
        while (t >= 1) {
            // 创建分数副本以避免修改原数据
            ArrayList<Integer> scoresCopy = new ArrayList<>(scores);
            // 检查是否可以分配
            if (canDistributeScores(scoresCopy, total, t)) {
                return total / t;
            }
            t--; // 减少队伍数量
        }
        // 如果无法分组,返回总分
        return total;
    }

    // 检查是否可以将分数分配到 teams 个队伍中
    private static boolean canDistributeScores(ArrayList<Integer> scores, int total, int teams) {
        // 如果总分不能被整除或目标分数小于最大分数,直接返回 false
        if (total % teams != 0) return false;

        int targetScore = total / teams;
        if (targetScore < scores.get(0)) return false;

        // 如果某些分数直接等于目标值,优先分配到队伍中
        while (!scores.isEmpty() && scores.get(0) == targetScore) {
            scores.remove(0);
            teams--;
        }

        // 初始化队伍得分数组
        int[] buckets = new int[teams];
        // 使用回溯分配分数
        return distribute(scores, 0, buckets, targetScore);
    }

    // 回溯分配分数到队伍
    private static boolean distribute(ArrayList<Integer> scores, int index, int[] buckets, int target) {
        // 如果所有分数都已分配,返回 true
        if (index == scores.size()) return true;

        int currentScore = scores.get(index);

        // 尝试将当前分数分配到每个队伍
        for (int i = 0; i < buckets.length; i++) {
            // 跳过重复的队伍分配(优化剪枝)
            if (i > 0 && buckets[i] == buckets[i - 1]) continue;
            // 如果当前分数可以加入队伍
            if (buckets[i] + currentScore <= target) {
                buckets[i] += currentScore;
                // 递归分配下一个分数
                if (distribute(scores, index + 1, buckets, target)) return true;
                // 回溯,移除当前分数
                buckets[i] -= currentScore;
            }
        }
        return false;
    }
}

C++解法

  • 解题思路
更新中

C解法

  • 解题思路

更新中

JS解法

  • 解题思路

  • 该问题的目标是将分数数组 pts 分成最多 mins 个队伍,使得每个队伍的分数尽可能相等,最终返回每个队伍的最大可能分数。

具体思路:

计算总分:
首先计算所有分数的总和 sum。
从最多 mins 个队伍开始尝试,逐步减少队伍数量,直到找到最大可能分数。
检查分配是否可行:
如果 sum 不能被当前队伍数量整除,跳过。
如果可以整除,目标分数为 sum / p,尝试分配分数。
递归回溯分配:
使用回溯算法尝试将分数分配到每个队伍。
剪枝优化:
跳过重复的分配方案。
如果当前队伍的分数加上当前分数大于目标分数,则直接跳过

const readline = require('readline');

// 主函数:处理输入并调用逻辑
function main() {
    const rl = readline.createInterface({
        input: process.stdin,
        output: process.stdout,
    });

    let t; // 用于存储队伍的数量
    rl.on('line', (line) => {
        if (!t) {
            // 读取第一行输入,队伍数量
            t = parseInt(line);
        } else {
            // 读取第二行输入,分数列表
            const pts = line.split(' ').map(Number);
            const res = calcMVP(t, pts);
            console.log(res);
            rl.close();
        }
    });
}

// 计算 MVP 分数的函数
function calcMVP(mins, pts) {
    // 计算总分
    const sum = pts.reduce((a, b) => a + b, 0);

    // 尝试从最多队伍数量逐步减少
    for (let p = mins; p >= 1; p--) {
        // 检查是否可以将分数均分为 p 个队伍
        if (sum % p === 0 && valid(p, sum / p, [...pts])) {
            return sum / p; // 如果可以分配,返回每个队伍的分数
        }
    }
    return sum; // 如果无法分配,返回总分
}

// 检查是否能合理分配分数
function valid(pl, tgt, pts) {
    // 按分数从大到小排序,方便优先分配高分
    pts.sort((a, b) => b - a);

    // 如果最高分大于目标分数,直接返回 false
    if (pts[0] > tgt) return false;

    // 初始化每个队伍的当前得分
    const alloc = new Array(pl).fill(0);

    // 使用回溯算法检查是否可以分配
    return dfs(0, pts, tgt, alloc);
}

// 递归分配函数
function dfs(idx, pts, tgt, alloc) {
    // 如果所有分数都已成功分配,返回 true
    if (idx === pts.length) return true;

    // 获取当前分数
    const current = pts[idx];

    // 尝试将当前分数分配到每个队伍
    for (let i = 0; i < alloc.length; i++) {
        // 跳过重复的队伍分配方案
        if (i > 0 && alloc[i] === alloc[i - 1]) continue;

        // 如果当前队伍可以接受当前分数
        if (alloc[i] + current <= tgt) {
            alloc[i] += current; // 将分数分配给队伍
            // 递归分配下一个分数
            if (dfs(idx + 1, pts, tgt, alloc)) return true;
            alloc[i] -= current; // 回溯,移除当前分数
        }
    }
    return false; // 如果无法分配,返回 false
}

// 启动主函数
main();

注意:

如果发现代码有用例覆盖不到的情况,欢迎反馈!会在第一时间修正,更新。
解题不易,如对您有帮助,欢迎点赞/收藏


http://www.kler.cn/a/452720.html

相关文章:

  • centos制作离线安装包
  • 洛谷 P1014:Cantor 表
  • 12.25周三F34-Day36打卡
  • 全面掌握 AutoGluon:从入门到生产环境的实践指南
  • 探索多模态大语言模型(MLLMs)的推理能力
  • Echarts连接数据库,实时绘制图表详解
  • Chrome+Postman做接口测试
  • 海格通信嵌入式面试题及参考答案
  • Ubuntu系统下 npm install -g tauri 报错问题处理
  • pnpm、Yarn 和 npm 的区别?
  • MySQL用表组织数据
  • 面试经典问题 —— 最大/小前K个数问题(top - K)问题
  • postgresql ERROR: cannot drop the currently open database
  • Java处理视频思路
  • 【接口自动化连载】使用yaml配置文件自动生成接口case
  • Postman最新接口自动化持续集成
  • 虚拟机桥接模式网络连接不上解决方法
  • SQL server学习10-数据库编程(中)
  • 常用的 JVM 调优的参数
  • 【C++多重类循环依赖问题】基于class前向声明与类定义和实现分离的解决方案与分析
  • 解决 Docker 中 DataLoader 多进程错误:共享内存不足
  • ES 集群 A 和 ES 集群 B 数据流通
  • 【数据分析】似然和极大似然估计
  • SQLSERVER、MYSQL LIKE查询特殊字符和转义字符相同与不同
  • 用Python开发高级游戏:实现3D迷宫游戏
  • 【Ubuntu】如何轻松设置80和443端口的防火墙