http://acm.hdu.edu.cn/showproblem.php?pid=1171
题意:有n种物品,给出每种物品的价值和数目,要将这些物品尽可能的分成相等的两份A和B且A>=B ,输出A,B。
母函数可以过,但感觉最直接的方法应该是多重背包。
母函数的话,也是按总价值的一半求,从一半到小枚举,直到找到系数不为0的就是B。
#include <stdio.h>
#include <iostream>
#include <map>
#include <set>
#include <stack>
#include <vector>
#include <math.h>
#include <string.h>
#include <queue>
#include <string>
#include <stdlib.h>
#include <algorithm>
#define LL long long
#define _LL __int64
#define eps 1e-12
#define PI acos(-1.0)
using namespace std;
int main()
{
int n;
int val[55],num[55];
int sum;
int c1[125010],c2[125010];
while(~scanf("%d",&n))
{
if(n < 0) break;
sum = 0;
for(int i = 1; i <= n; i++)
{
cin >> val[i] >> num[i];
sum += val[i]*num[i];
}
int tmp = sum/2;
memset(c1,0,sizeof(c1));
memset(c2,0,sizeof(c2));
for(int i = 0; i <= val[1]*num[1]; i += val[1])
c1[i] = 1;
for(int i = 2; i <= n; i++)
{
for(int j = 0; j <= tmp; j++)
{
for(int k = 0; k+j <= tmp && k <= val[i]*num[i]; k += val[i])
c2[k+j] += c1[j];
}
for(int j = 0; j <= tmp; j++)
{
c1[j] = c2[j];
c2[j] = 0;
}
}
int i;
for(i = tmp; i >= 0; i--)
if(c1[i] != 0)
break;
printf("%d %d\n",sum-i,i);
}
return 0;
}
多重背包,按总价值的一半进行背包,相比母函数时间更快,一维的相比二维的时间更快。
未优化的多重背包:
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int val[55],num[55];
int dp[125010];
int n;
int main()
{
while(~scanf("%d",&n))
{
if(n < 0) break;
int sum = 0;
for(int i = 1; i <= n; i++)
{
scanf("%d %d",&val[i],&num[i]);
sum += val[i]*num[i];
}
int tmp = sum/2;
memset(dp,0,sizeof(dp));
dp[0] = 1;
int ans = -1;
for(int i = 1; i <= n; i++)
{
for(int j = 0; j <= num[i]; j++)
{
for(int v = tmp; v >= j*val[i]; v--) //逆序
if(dp[v-j*val[i]])
{
dp[v] = 1;
ans = max(ans,v);
}
}
}
printf("%d %d\n",sum-ans,ans);
}
return 0;
}