题目描述
部门准备举办一场王者荣耀表演赛,有10名游戏爱好者参与,分为两队,每队5人。每位参与者都有一个评分,代表他的游戏水平。为了表演赛尽可能精彩,我们需要将10名参赛者分为实力尽量相近的两队。一队的实力可以表示为这一队5名队员的评分总和。现在给定10名参与者的游戏水平评分,请根据上述要求分队,最后输出这两组的实力差绝对值的最小值。
示例 1:
输入: [5, 1, 8, 3, 4, 6, 7, 10, 9, 2]
输出: 1
解释: 分组为 (1, 3, 5, 8, 10)
和 (2, 4, 6, 7, 9)
,两组实力差为 1
。
示例 2:
输入: [3, 3, 3, 3, 3, 3, 3, 3, 3, 9]
输出: 6
解释: 分组为 (3, 3, 3, 3, 9)
和 (3, 3, 3, 3, 3)
,两组实力差为 6
。
解题思路
-
问题分析:
- 需要将10个评分分成两组,每组5人,使得两组的总评分差最小。
- 直接暴力搜索所有可能的组合会生成 ( C_{10}^5 = 252 ) 种组合,对于给定的输入规模是可接受的。
-
算法选择:
- 使用回溯法生成所有可能的5人组合,计算每组的总评分,并记录最小的差值。
-
步骤详解:
- 计算所有评分的总和
total
。 - 使用回溯法生成所有5人组合的总评分,存入列表
sumList
。 - 遍历
sumList
,计算每组总评分与total / 2
的差值,更新最小差值minDiff
。
- 计算所有评分的总和
代码实现
Java
import java.util.Scanner;
public class 王者荣耀匹配机制 {
private static int min = Integer.MAX_VALUE;
private static int totalSum = 0;
private static final int ARR_LENGTH = 10;
private static final int SINGLE_GROUP_LENGTH = 5;
private static int[] arr = new int[ARR_LENGTH];
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
for (int i = 0; i < arr.length; i++) {
arr[i] = scanner.nextInt();
totalSum += arr[i];
}
int partSum = 0;
backtrace(0, 0, partSum);
System.out.println(min);
}
private static void backtrace(int start, int count, int partSum) {
if (count == SINGLE_GROUP_LENGTH) {
int currentMin = Math.abs(2 * partSum - totalSum);
min = Math.min(min, currentMin);
return;
}
for (int i = start; i < ARR_LENGTH; i++) {
backtrace(start + 1, count + 1, partSum + arr[i]);
}
}
}
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
private static List<Integer> sumList = new ArrayList<>();
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int[] nums = new int[10];
for (int i = 0; i < 10; i++) {
nums[i] = scanner.nextInt();
}
int total = 0;
for (int num : nums) {
total += num;
}
backtrack(nums, 0, 0, 0);
int minDiff = Integer.MAX_VALUE;
for (int sum : sumList) {
int diff = Math.abs(total - 2 * sum);
if (diff < minDiff) {
minDiff = diff;
}
}
System.out.println(minDiff);
}
private static void backtrack(int[] nums, int start, int count, int currentSum) {
if (count == 5) {
sumList.add(currentSum);
return;
}
for (int i = start; i < nums.length; i++) {
backtrack(nums, i + 1, count + 1, currentSum + nums[i]);
}
}
}
Python
def main():
nums = list(map(int, input().split()))
total = sum(nums)
sum_list = []
def backtrack(start, count, current_sum):
if count == 5:
sum_list.append(current_sum)
return
for i in range(start, 10):
backtrack(i + 1, count + 1, current_sum + nums[i])
backtrack(0, 0, 0)
min_diff = float('inf')
for s in sum_list:
diff = abs(total - 2 * s)
if diff < min_diff:
min_diff = diff
print(min_diff)
if __name__ == "__main__":
main()
C++
#include <iostream>
#include <vector>
#include <climits>
using namespace std;
vector<int> sumList;
void backtrack(int nums[], int start, int count, int currentSum) {
if (count == 5) {
sumList.push_back(currentSum);
return;
}
for (int i = start; i < 10; i++) {
backtrack(nums, i + 1, count + 1, currentSum + nums[i]);
}
}
int main() {
int nums[10];
for (int i = 0; i < 10; i++) {
cin >> nums[i];
}
int total = 0;
for (int num : nums) {
total += num;
}
backtrack(nums, 0, 0, 0);
int minDiff = INT_MAX;
for (int sum : sumList) {
int diff = abs(total - 2 * sum);
if (diff < minDiff) {
minDiff = diff;
}
}
cout << minDiff << endl;
return 0;
}
JavaScript
function main() {
const nums = prompt("Enter 10 numbers separated by spaces").split(' ').map(Number);
const total = nums.reduce((a, b) => a + b, 0);
const sumList = [];
function backtrack(start, count, currentSum) {
if (count === 5) {
sumList.push(currentSum);
return;
}
for (let i = start; i < 10; i++) {
backtrack(i + 1, count + 1, currentSum + nums[i]);
}
}
backtrack(0, 0, 0);
let minDiff = Infinity;
for (const sum of sumList) {
const diff = Math.abs(total - 2 * sum);
if (diff < minDiff) {
minDiff = diff;
}
}
console.log(minDiff);
}
main();
复杂度分析
-
时间复杂度:
- 生成所有组合的时间复杂度为 ( O(C_{10}^5) = O(252) ),遍历
sumList
的时间复杂度为 ( O(252) ),因此总时间复杂度为 ( O(1) )(因为输入规模固定为10)。
- 生成所有组合的时间复杂度为 ( O(C_{10}^5) = O(252) ),遍历
-
空间复杂度:
- 存储所有组合的总评分需要 ( O(C_{10}^5) = O(252) ) 的空间,因此空间复杂度为 ( O(1) )。
测试用例示例
测试用例 1:
输入: 5 1 8 3 4 6 7 10 9 2
预期输出: 1
测试用例 2:
输入: 3 3 3 3 3 3 3 3 3 9
预期输出: 6
测试用例 3:
输入: 1 2 3 4 5 6 7 8 9 10
预期输出: 1
问题总结
- 核心要点:将10个评分分成两组,每组5人,使得两组总评分差最小。
- 解题关键:使用回溯法生成所有可能的5人组合,计算总评分差的最小值。
- 优化方向:对于更大的输入规模,可以考虑动态规划或剪枝优化,但本题输入规模固定为10,回溯法足够高效。
- 适用性:适用于固定规模的分组问题,但对于更大规模的问题,需要更高效的算法。