題意:
給你一堆硬幣,讓你分成兩堆,分別給A,B兩個人,求兩人得到的最小差。
分析:
首先算出每個硬幣的權值之和sum。然後以sum / 2爲揹包容量,求出能裝出的最大包。答案就是sum - 最大包 * 2
原理:
如果剛好可以將硬幣分爲sum / 2和sum / 2那就最好了,答案直接是0。但如果分不到,那麼其中一組的權值和肯定是sum / 2的前驅(也就是能湊出的最大的權值和且<=sum / 2)。所以,揹包算出這個前驅即可。那麼最小差就是另一組權值和 - 前驅 = sum - 前驅 * 2
AC代碼:
#include <iostream>
#include <vector>
#include <utility>
#include <cstring>
#include <algorithm>
#include <map>
#include <queue>
#include <stack>
#include <cstdio>
#include <fstream>
#include <set>
using namespace std;
typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define MAXN 50005
int w[MAXN];
int dp[MAXN];
int main() {
ios;
int T;
while (cin >> T) {
while (T--) {
memset(dp, 0, sizeof(dp));
int n;
cin >> n;
int avg = 0;
int sum = 0;
for (int i = 1; i <= n; i++) {
cin >> w[i];
sum += w[i];
}
avg = sum / 2;
for (int i = 1; i <= n; i++) {
for (int j = avg; j >= w[i]; j--)
dp[j] = max(dp[j], dp[j - w[i]] + w[i]);
}
cout << sum - 2 * dp[avg] << endl;
}
}
return 0;
}