题意
给你一些东西,每样东西都有它的权值和个数。
问你把它分成两个部分,要使两个部分的权值之和的差值最小。
问这种情况下的两个权值是多少?
思路
我们先算出总和。
然后把 总和的二分之一 当做背包的容量。
然后对所有数字,在这个背包容量下dp即可。
我这里用了多重背包的dp,在网上看到许多题解用了01背包来做,也可以,不过花费的时间是用多重背包dp的十倍,如果数据量再大一些些就T啦。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long ll;
const int maxn = 25e5 + 5;
int dp[maxn];
int a[maxn], c[maxn];
int main()
{
int n;
while(scanf("%d", &n) && n >= 0)
{
int sum = 0;
memset(dp, 0, sizeof(dp));
for(int i = 1; i <= n; i++)
{
scanf("%d %d", &a[i], &c[i]);
sum += a[i] * c[i];
}
int total = sum;
sum /= 2;
for(int i = 1; i <= n; i++)
{
int k = 1;
while(k <= c[i])
{
c[i] -= k;
int tem = k * a[i];
for(int j = sum; j >= tem; j--)
dp[j] = max(dp[j], dp[j - tem] + tem);
k <<= 1;
}
if(c[i] > 0)
{
k = c[i];
int tem = k * a[i];
for(int j = sum; j >= tem; j--)
dp[j] = max(dp[j], dp[j - tem] + tem);
}
}
printf("%d %d\n", total - dp[sum], dp[sum]);
}
return 0;
}