【华为OD-E卷 - 分苹果 100分(python、java、c++、js、c)】
题目
A、B两个人把苹果分为两堆,A希望按照他的计算规则等分苹果,他的计算规则是按照二进制加法计算,并且不计算进位 12+5=9(1100 + 0101 = 9),B的计算规则是十进制加法,包括正常进位,B希望在满足A的情况下获取苹果重量最多。
输入苹果的数量和每个苹果重量,输出满足A的情况下B获取的苹果总重量。
如果无法满足A的要求,输出-1。
数据范围
1 <= 总苹果数量 <= 20000 1 <= 每个苹果重量 <= 10000
输入描述
- 输入第一行是苹果数量:3
输入第二行是每个苹果重量:3 5 6
输出描述
- 输出第一行是B获取的苹果总重量:11
用例
用例一:
输入:
3
3 5 6
输出:
11
用例二:
输入:
8
7258 6579 2602 6716 3050 3564 5396 1773
输出:
35165
python解法
- 解题思路:
- 这段代码的目标是处理一组权重,判断是否能将其分成两个非空子集,使得两个子集的按位异或结果相等。如果可以,将两个子集的总和的最大值作为结果输出;如果不能,返回 -1。
核心思想是:
如果所有权重的异或值(xor_result)为 0,说明可以通过某种划分使两个子集的异或值相等。
若可以划分,去掉最小的权重值后,剩余权重的总和即为最大的子集总和。
如果异或值不为 0,说明无法划分,返回 -1。
# 输入权重的数量
n = int(input())
# 输入权重列表
weights = list(map(int, input().split()))
# 计算最大子集权重总和
def find_max_weight(weights):
# 对权重进行升序排序
sorted_weights = sorted(weights)
# 初始化异或结果和总和
xor_result = 0 # 存储所有权重的异或值
total = 0 # 存储所有权重的总和
# 遍历权重,计算异或值和总和
for weight in sorted_weights:
xor_result ^= weight # 累积异或值
total += weight # 累积总和
# 如果异或值为 0,说明可以划分为两个异或值相等的子集
if xor_result == 0:
return total - sorted_weights[0] # 最大子集总和为总和减去最小值
else:
return -1 # 如果异或值不为 0,无法划分
# 调用函数并输出结果
print(find_max_weight(weights))
java解法
- 解题思路
- 这段代码的目标是判断一组权重是否可以分成两个非空子集,使得两个子集的按位异或结果相等。如果可以,则返回两个子集总和的最大值;如果不能,则返回 -1。
核心思想
异或的性质:
如果一组数字的异或值为 0,说明可以划分为两个异或结果相等的子集。
异或运算满足交换律和结合律,因此排列顺序不影响结果。
最大子集总和计算:
如果异或值为 0,将权重总和减去最小值,得到最大子集总和。
如果异或值不为 0,说明无法划分,返回 -1。
排序的作用:
排序便于直接找到最小值,简化后续计算
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
// 输入权重的数量
int size = input.nextInt();
int[] weights = new int[size];
// 输入权重列表
for (int i = 0; i < size; i++) {
weights[i] = input.nextInt();
}
// 调用方法计算结果并输出
System.out.println(findMaxWeight(size, weights));
}
/**
* 计算最大子集总和或判断是否无法划分
*
* @param size 权重数组的大小
* @param weights 权重数组
* @return 最大子集总和或 -1
*/
public static int findMaxWeight(int size, int[] weights) {
// 对权重数组进行升序排序
Arrays.sort(weights);
// 初始化最小值、异或值和总权重
int minVal = weights[0]; // 最小值为排序后数组的第一个元素
int xorVal = minVal; // 初始异或值为最小值
int totalWeight = minVal; // 初始总权重为最小值
// 遍历剩余的权重,计算异或值和总权重
for (int i = 1; i < size; i++) {
xorVal ^= weights[i]; // 累积异或值
totalWeight += weights[i]; // 累积总权重
}
// 判断异或值是否为 0
return xorVal == 0 ? totalWeight - minVal : -1;
}
}
C++解法
- 解题思路
更新中
C解法
更新中
JS解法
核心思想
异或运算的性质:
异或运算满足交换律和结合律。
如果一组数字的异或值为 0,则说明可以划分为两个异或值相等的子集。
总和计算:
如果可以划分,总和的最大值是所有权重的总和减去最小值(即,将最小值分配到一个子集,其余权重分配到另一个子集)。
如果不能划分,直接返回 -1
const readline = require("readline");
// 创建 readline 接口,用于读取标准输入
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
// 存储输入的行
const lines = [];
// 每次读取一行时触发
rl.on("line", (line) => {
lines.push(line);
if (lines.length === 2) { // 当输入的行数达到两行时,开始处理
const n = parseInt(lines[0]); // 第 1 行:权重数量
const weights = lines[1].split(" ").map(Number); // 第 2 行:权重数组
console.log(computeWeights(n, weights)); // 调用主逻辑函数并输出结果
lines.length = 0; // 清空存储的行,准备接收下一组输入
}
});
/**
* 计算最大子集总和或判断是否无法划分
*
* @param {number} n 权重数量
* @param {number[]} weights 权重数组
* @return {number} 最大子集总和或 -1
*/
function computeWeights(n, weights) {
// 找到最小的权重值
const minWeight = Math.min(...weights);
// 初始化异或值和总权重
let bitwiseSum = 0; // 用于存储所有权重的按位异或值
let totalSum = 0; // 用于存储所有权重的总和
// 遍历权重数组,累积异或值和总和
for (let weight of weights) {
bitwiseSum ^= weight; // 按位异或累积
totalSum += weight; // 累积总和
}
// 判断异或值是否为 0
if (bitwiseSum === 0) {
// 如果异或值为 0,返回最大子集总和(总和减去最小值)
return totalSum - minWeight;
} else {
// 如果异或值不为 0,返回 -1
return -1;
}
}
注意:
如果发现代码有用例覆盖不到的情况,欢迎反馈!会在第一时间修正,更新。
解题不易,如对您有帮助,欢迎点赞/收藏