华为OD机试(C卷+D卷)2024真题目录(Java & c++ & python)
题目描述
MELON有一堆精美的雨花石(数量为n,重量各异),准备送给S和W。MELON希望送给俩人的雨花石重量一致,请你设计一个程序,帮MELON确认是否能将雨花石平均分配。
输入描述
第1行输入为雨花石个数:n, 0 < n < 31。
第2行输入为空格分割的各雨花石重量:m[0] m[1] …… m[n - 1], 0 < m[k] < 1001。
不需要考虑异常输入的情况。
输出描述
如果可以均分,从当前雨花石中最少拿出几块,可以使两堆的重量相等;如果不能均分,则输出-1。
用例1
输入
4
1 1 2 2
输出
2
说明 输入第一行代表共4颗雨花石,
第二行代表4颗雨花石重量分别为1、1、2、2。
均分时只能分别为1,2,需要拿出重量为1和2的两块雨花石,所以输出2。
用例2
输入
10
1 1 1 1 1 9 8 3 7 10
输出
3
说明 输入第一行代表共10颗雨花石,
第二行代表4颗雨花石重量分别为1、1、1、1、1、9、8、3、7、10 。
均分时可以1,1,1,1,1,9,7和10,8,3,也可以1,1,1,1,9,8和10,7,3,1,或者其他均分方式,但第一种只需要拿出重量为10,8,3的3块雨花石,第二种需要拿出4块,所以输出3(块数最少)。
解题思路
首先,将所有雨花石重量之和求出,设为sum,
- 如果sum % 2 != 0,则说明无法平分,直接返回-1。
- 如果sum % 2 == 0,则说明“可能”平分。
如果“可能”平分,此时,我们可以将本问题转化为:01背包问题中“装满背包的最少物品数问题”。
其中:
- 背包承重 = sum / 2
- 物品 = 所有雨花石
- 物品重量 = 雨花石重量
01背包的学习可以参考:背包相关问题的详细学习
我们假设dp[i][j] 表示从 0 ~ i 物品中选择,能装满背包承重 j 的最少物品数量。那么:
- 如果第 i 个物品(重量为w)选择的话,则 dp[i][j] = dp[i-1][j - w] + 1;(ps:+1代表背包装入了第i个物品)
- 如果第 i 个物品不选的话,则 dp[i][j] = dp[i-1][j];
最终 dp[i][j] 取最小值即可,即:dp[i][j] = min(dp[i-1][j],dp[i-1][j - w] + 1)
另外,我们需要注意dp的初始化,因为后面要求最少物品数量,因此如果将dp[0][1] ~ dp[0][bag] 初始化为0,则会影响后续取最小值(ps:0必然是最少的数量)。
因为我们应该将dp[0][1] ~ dp[0][bag]初始化为一个不可能的较大值,这里由于背包承重是sum/2,因此背包绝对不可能装入 n 个雨花石,因为n个雨花石的重量之和为sum。
参考代码
#include <bits/stdc++.h>
using namespace std;
int getResult(int n, vector<int>& stoneWeights) {
// 所有雨花石重量之和
int totalWeight = accumulate(stoneWeights.begin(), stoneWeights.end(), 0);
// 如果重量之和不能整除2,则必然无法平分
if (totalWeight % 2 != 0) {
return -1;
}
// 背包承重
int halfWeight = totalWeight / 2;
// 二维数组,dp[i][j]表示使用前i个雨花石能否组成重量为j的背包
vector<vector<int>> dp(n + 1, vector<int>(halfWeight + 1, n));
// 初始化:不使用任何雨花石时,组成重量为0的背包需要0个雨花石
dp[0][0] = 0;
// 动态规划填表
for (int i = 1; i <= n; ++i) {
int weight = stoneWeights[i - 1];
for (int j = 0; j <= halfWeight; ++j) {
if (j < weight) {
dp[i][j] = dp[i - 1][j];
} else {
dp[i][j] = min(dp[i - 1][j], dp[i - 1][j - weight] + 1);
}
}
}
// 如果装满背包的最少物品数为n, 则说明没有平分方案
if (dp[n][halfWeight] == n) {
return -1;
} else {
return dp[n][halfWeight];
}
}
int main() {
// 输入获取
int n;
cin >> n;
vector<int> stoneWeights(n);
for (int i = 0; i < n; ++i) {
cin >> stoneWeights[i];
}
// 调用算法并输出结果
cout << getResult(n, stoneWeights) << endl;
return 0;
}