传送门
题意: 好像面试题就有这道题? 就是给定2*n个人, 每个人有一个值, 要你分成两堆, 并且要这两堆的值相加的差值要尽量的小, 问这个最小差值是多少.
思路: 还是很经典的一个dp, 那就是dp[i][j][k] 表示前i个人中选min(i, n)个人能否组合出 值为 k 的组法. 所以很明显对于当前这个值, 如果k-a[i] 是存在的, 那么就可以选上这个值就行一个组合, 否则不能选就只能继续继承上一个的状态. 所以转移方程是:
dp[i][j][k] = dp[i-][j][k];
if ( k >= a[i] && dp[i-1][j-1][k-a[i]) dp[i][j][k] = 1;
最后根据这个dp数组的含义找一遍就可以得到答案了….. 细节请看代码实现.
AC Code
const int maxn = 1e5+5;
bitset<505>dp[32][16];
int a[35];
void solve()
{
int n;
scanf("%d", &n); int sum = 0;
dp[0][0][0] = 1;
for (int i = 1 ; i <= 2*n ; i ++) {
scanf("%d", &a[i]);
sum += a[i];
dp[i][0][0] = 1;
}
for (int i = 1 ; i <= 2*n ; i ++) {
for (int j = 1 ; j <= min(i, n) ; j ++) {
for (int k = 1 ; k <= sum/2 ; k ++) {
dp[i][j][k] = dp[i-1][j][k];
if (k >= a[i] && dp[i-1][j-1][k-a[i]]) {
dp[i][j][k] = 1;
}
}
}
}
int ans = 0;
for (int i = 1 ; i <= sum / 2 ; i ++) {
if (dp[2*n][n][i]) ans = i;
}
printf("%d\n", abs(sum - 2*ans));
}