题目
小v最近在玩一款挖矿的游戏,该游戏介绍如下:
1、每次可以挖到多个矿石,每个矿石的重量都不一样,挖矿结束后需要通过一款平衡矿车运送下山;
2、平衡矿车有左右2个车厢,中间只有1个车轮沿着导轨滑到山下,且矿车只有在2个车厢重量完全相等且矿石数量相差不超过1个的情况下才能成功运送矿石,否则在转弯时可能出现侧翻。
假设小v挖到了n(n<100)个矿石,每个矿石重量不超过100,为了确保一次性将n个矿石都运送出去,一旦矿车的车厢重量不一样就需要购买配重砝码。请问小v每次最少需要购买多少重量的砝码呢? (假设车厢足够放下这些矿石和砝码,砝码重量任选)
解法
这道题我没做出来,感觉自己对于背包问题的解答思路还是比较欠缺的。所以写个文章梳理一下。下面是大佬AC的代码,n表示矿石数量,weight记录每块矿石的重量。
int solution(int n, int weight[]) {
int s = 0;
for (int i = 0; i < n; ++i) {
s += weight[i];
}
// S 为矿石总重量的一半
int S = s >> 1;
// N 为矿石数量的一半
int N = (n + 1) >> 1;
//建立(S+1)*(N+1)的动态二维数组
// dp[i][j] 代表什么呢
vector<vector<int> > dp(S + 1, vector<int>(N + 1, -INF));
// 数组第一行置为0
for (int i = 0; i <= S; ++i) dp[i][0] = 0;
for (int i = 0; i < n; ++i) {
auto dp1 = dp;
// j的取值范围[ weight[i], S],为什么呢
for (int j = weight[i]; j <= S; ++j) {
for (int k = 1; k <= N; ++k) {
dp1[j][k] = max(dp1[j][k], dp[j - weight[i]][k - 1] + weight[i]);
}
}
// 用旧的dp数组来进行for循环,循环完毕更新整个dp数组
swap(dp1, dp);
}
if (n & 1) {
return s - 2 * max(dp[S][N], dp[S][N - 1]);
}
return s - 2 * dp[S][N];
}