• 华为OD机考算法题:篮球比赛


    目录

    题目部分

    解读与分析

    代码实现


    题目部分

    题目篮球比赛
    难度
    题目说明篮球(5V5)比赛中,每个球员拥有一个战斗力,每个队伍的所有球员战斗力之和为该队伍的总体战斗力。现有 10 个球员准备分为两队进行训练赛,教练希望 2 个队伍的战斗力差值能够尽可能的小,以达到最佳训练效果。给出 10 个球员的战斗力,如果你是教练,你该如何分队,才能达到最佳训练效果?请说出该分队方案下的最小战斗力差值。
    输入描述10 个篮球队员的战斗力(整数,范围[1,10000])战斗力之间用空格分隔,如:10 9 8 7 6 5 4 3 2 1。
    不需要考虑异常输入的场景。
    输出描述输出描述最小的战斗力差值,如:1。
    补充说明
    ------------------------------------------------------
    示例
    示例1
    输入10 9 8 7 6 5 4 3 2 1
    输出1
    说明1、2、5、9、10 分为一队,3、4、6、7、8分为一队,两队战斗力之差最小,输出差值1。备注:球员分队方案不唯一,但最小战斗力差值固定是1。


    解读与分析

    题目解读

    10 个数字分成两组,每组 5 个数字,使两组数字之和的差值最小。请输出最小差值。 

    分析与思路

    本题与《华为OD机考算法题:MVP争夺战》类似,都是把数字分组,要求分组后的数字达到某种要求。不同的是,在《MVP争夺战》中,每组的数字个数是不定的,而在本题中,每组数字的个数是固定的,都是 5。相对而言,本题的思路和实现更简单。

    从 10 个数中,穷尽所有的情况,每种情况计算一下两队的差值,找出差值最小的那个。

    假设这两组分别为 A 组和 B 组,这 10 个数字分别为 T_{1}T_{2}……T_{10}
    我们穷尽的顺序是,先把 T_{1} 放到 A 组,然后基于剩下的 9 个数字,采用相同的方法,穷尽 9 个数字取 4 个的所有可能情况。这样从 10 个数字中取 5 个的情况就降维成了 9 个数字取 4 个,同样的方法,最后可以降为成 6 个数字里取 1 个。
    以上是 T_{1}  放到 A 组的情况,接下来就是 T_{2} 放到 A 组,然后从 T_{3} 到 T_{10} 这 8 个数字中,穷尽 8 个数字 取 4 个数字的所有可能情况。

    每遍历一种情况,计算两组的数字之差(设为 diff)时,如果 diff 比之前遍历时计算的最小差(设为minDiff)更小,那么更新 minDiff 的值。遍历完所有情况后,最终求得的 minDiff 值即为题目所要求的输出。这种算法遍历的次数为 C_{10}^{5}

    在以上的遍历算法中,存在重复计算的情况。题目只关心两组的差值,所以在任意一种组合,把 A 组的数字和 B 组的数字交换,可以看做是同一种情况。如 T_{1}T_{2}T_{3}T_{4}T_{5} 放到 A 组 与 T_{6}T_{7}T_{8}T_{9}T_{10} 放到 A 组其实是等同的。为了减少重复,我们可以假设 A 组的数字之和小于或等于 B 组的数字之和,即 A 组数字之和小于或等于所有数字之和(设为 sum)的一半。那么在穷举所有情况时,发现 A 组数字之和已经超过 (sum/2),那么就可以忽略这种组合了。这样可以减少一半遍历,遍历次数变为 \frac{C_{10}^{5}}{2}

    既然需要保证A组数字之和小于或等于 (sum/2),我们可以先对数字进行从小到大排序,进一步减少遍历次数。

    综上,此算法的遍历次数不超过 \frac{C_{10}^{5}}{2}。下面,我们计算一下最大遍历次数。

    由组合计算公式 C_{m}^{n} = \frac{m!}{n!(m-n)!},可以得出  \frac{C_{10}^{5}}{2} = \frac{ 10!}{(5!)(5!)*2} = 126,最多不超过 126 次。


    代码实现

    Java代码

    1. import java.util.ArrayList;
    2. import java.util.Arrays;
    3. import java.util.List;
    4. import java.util.Scanner;
    5. /**
    6. * 篮球比赛
    7. * @since 2023.09.15
    8. * @version 0.1
    9. * @author Frank
    10. *
    11. */
    12. public class BasketballGame {
    13. public static void main(String[] args) {
    14. Scanner sc = new Scanner(System.in);
    15. while (sc.hasNext()) {
    16. String input = sc.nextLine();
    17. String[] strNumbers = input.split( " " );
    18. // 此处 count == numbers.count,可以完全不用考虑 count.
    19. processBasketballGame( strNumbers );
    20. }
    21. }
    22. private static void processBasketballGame( String strNumbers[] )
    23. {
    24. Integer[] numbers = new Integer[strNumbers.length];
    25. int sum = 0;
    26. for( int i = 0; i < numbers.length; i ++ )
    27. {
    28. numbers[i] = Integer.parseInt( strNumbers[i] );
    29. sum += numbers[i];
    30. }
    31. Arrays.sort( numbers );
    32. int minDiff = sum; // minDiff 一定小于 sum
    33. List<Integer> numList = new ArrayList<Integer>( Arrays.asList( numbers ) );
    34. minDiff = getMinDiff( sum, minDiff, 0, 0, numList );
    35. System.out.println( minDiff );
    36. }
    37. private static int getMinDiff( int SUM, int minDiff, int currentSum, int currentCnt, List<Integer> numbers )
    38. {
    39. if( currentCnt + numbers.size() < 5 )
    40. {
    41. return SUM;
    42. }
    43. List<Integer> tmpRemovedNumber = new ArrayList<Integer>();
    44. for( int i = 0; i < numbers.size(); i ++ )
    45. {
    46. int tmpMinDiff = SUM;
    47. int tmpNumber = numbers.get( i );
    48. int tmpCurrentSum = currentSum + tmpNumber;
    49. int tmpCurrentCnt = currentCnt + 1;
    50. if( tmpCurrentSum * 2 > SUM )
    51. {
    52. break; // 可以break,因为后面的数字更大。
    53. }
    54. if( tmpCurrentCnt == 5 )
    55. {
    56. tmpMinDiff = SUM - tmpCurrentSum * 2;
    57. if( tmpMinDiff < minDiff )
    58. {
    59. minDiff = tmpMinDiff;
    60. continue;
    61. }
    62. }
    63. tmpRemovedNumber.add( tmpNumber );
    64. numbers.remove( i );
    65. tmpMinDiff = getMinDiff( SUM, minDiff, tmpCurrentSum, tmpCurrentCnt, numbers );
    66. if( tmpMinDiff < minDiff )
    67. {
    68. minDiff = tmpMinDiff;
    69. }
    70. // numbers.add( i, tmpNumber ); // 不必加回去,可以减少一半的穷举数
    71. }
    72. for( int i = 0; i < tmpRemovedNumber.size(); i ++ )
    73. {
    74. numbers.add( i, tmpRemovedNumber.get( i ) );
    75. }
    76. return minDiff;
    77. }
    78. }

    JavaScript代码

    1. const rl = require("readline").createInterface({ input: process.stdin });
    2. var iter = rl[Symbol.asyncIterator]();
    3. const readline = async () => (await iter.next()).value;
    4. void async function() {
    5. while (line = await readline()) {
    6. // count 可以忽略
    7. var strNumbers = line.split(" ");
    8. processBasketballGame(strNumbers);
    9. }
    10. }();
    11. function processBasketballGame(strNumbers) {
    12. var numbers = new Array();
    13. var sum = 0;
    14. for (var i = 0; i < strNumbers.length; i++) {
    15. numbers[i] = parseInt(strNumbers[i]);
    16. sum += numbers[i];
    17. }
    18. numbers.sort();
    19. var minDiff = sum; // minDiff 一定小于 sum
    20. minDiff = getMinDiff(sum, minDiff, 0, 0, numbers);
    21. console.log(minDiff);
    22. }
    23. function getMinDiff(SUM, minDiff, currentSum, currentCnt, numbers) {
    24. if (currentCnt + numbers.length < 5) {
    25. return SUM;
    26. }
    27. var tmpRemovedNumber = new Array();
    28. for (var i = 0; i < numbers.length; i++) {
    29. var tmpMinDiff = SUM;
    30. var tmpNumber = numbers[i];
    31. var tmpCurrentSum = currentSum + tmpNumber;
    32. var tmpCurrentCnt = currentCnt + 1;
    33. if (tmpCurrentSum * 2 > SUM) {
    34. break; // 可以break,因为后面的数字更大。
    35. }
    36. if (tmpCurrentCnt == 5) {
    37. tmpMinDiff = SUM - tmpCurrentSum * 2;
    38. if (tmpMinDiff < minDiff) {
    39. minDiff = tmpMinDiff;
    40. continue;
    41. }
    42. }
    43. tmpRemovedNumber.push(tmpNumber);
    44. numbers.splice(i, 1);
    45. tmpMinDiff = getMinDiff(SUM, minDiff, tmpCurrentSum, tmpCurrentCnt, numbers);
    46. if (tmpMinDiff < minDiff) {
    47. minDiff = tmpMinDiff;
    48. }
    49. }
    50. for (var i = 0; i < tmpRemovedNumber.length; i++) {
    51. numbers.splice(i, 0, tmpRemovedNumber[i]);
    52. }
    53. return minDiff;
    54. }

    (完)

  • 相关阅读:
    注册器模式
    2023.11.19 hadoop之MapReduce
    人脸识别之light_cnn
    Java使用WebSocket(基础)
    【Linux】服务器被work32病毒入侵CPU占用99%
    分饼干问题(DP)
    风力等级划分
    第十一节:抽象类和接口【java】
    pytorch初学笔记(十二):神经网络基本结构之线性层
    【第四篇】商城系统-品牌管理实现
  • 原文地址:https://blog.csdn.net/ZiJinShi/article/details/132901418