题意很简单,n种物品,每个物品对应一个价值和数量。让你竟可能的分成相等的两份。
可以设背包容量为sum/2用多重背包解决。
也可以用母函数来解决,计算能组成的最接近sum/2的值。
母函数可以解决很多背包问题。。但是速度一般比用dp做慢好多。。
母函数代码:1800ms
#include
using namespace std;
const int maxn = 1e5+5;
int v[55], m[55], n, c1[maxn], c2[maxn];
int main(void)
{
while(cin >> n)
{
int sum = 0;
if(n < 0) break;
for(int i = 1; i <= n; i++)
scanf("%d%d", &v[i], &m[i]), sum += v[i]*m[i];
int mid = sum/2;
memset(c1, 0, sizeof(c1));
memset(c2, 0, sizeof(c2));
for(int i = 0; i <= mid && i/v[1] <= m[1]; i += v[1])
c1[i] = 1;
for(int i = 2; i <= n; i++)
{
for(int j = 0; j <= mid; j++)
for(int k = 0; k+j <= mid && k/v[i] <= m[i]; k += v[i])
c2[k+j] += c1[j];
for(int j = 0; j <= mid; j++)
c1[j] = c2[j], c2[j] = 0;
}
for(int i = mid; i >= 0; i--)
{
if(c1[i])
{
printf("%d %d", sum-i, i);
break;
}
}
printf("\n");
}
return 0;
}
多重背包代码:90ms
#include
using namespace std;
const int maxn = 1e5+5;
int dp[maxn], v[maxn], d[maxn], V[maxn];
int main(void)
{
int n;
while(cin >> n, n >= 0)
{
memset(dp, 0, sizeof(dp));
int sum = 0;
for(int i = 1; i <= n; i++)
scanf("%d%d", &v[i], &d[i]), sum += v[i]*d[i];
int mid = sum/2, count = 0;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= d[i]; j*=2)
{
V[count++] = j*v[i];
d[i] -= j;
}
if(d[i] > 0) V[count++] = d[i]*v[i];
}
for(int i = 0; i < count; i++)
for(int j = mid; j >= V[i]; j--)
dp[j] = max(dp[j], dp[j-V[i]]+V[i]);
printf("%d %d\n", sum-dp[mid], dp[mid]);
}
return 0;
}