http://acm.hdu.edu.cn/showproblem.php?pid=1171
题目意思:
要求:把给出的物品分给两个学院,保证前个必须大于后一个院。给出的数据是:物品的价值,和数目.
思路:一开始我想到直接一维背包,后来想想,不行,万一在球的中途求得只并非最大,但是你有判断不了。因此这里可能不能直接一维背包不能解决,但是必须加是上完全背包,对每一个组数据,进行判断(与总和的一半),这样就分成两中情况。不会道导致超出的。
分析:根据完全背包与一维背包的定义!!可以的的出。
详细见代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std ;
const int maxn=55;
int dp[150005];
int val[maxn];
int num[maxn];
int n;
int main()
{
int i,j,k,x,y,sum,ans;
while(scanf("%d",&n)!=EOF)
{
if(n<0)break;
ans=0;
for(i=1;i<=n;i++)
{
scanf("%d%d",&val[i],&num[i]);
ans+=val[i]*num[i];
}
sum=ans/2;
memset(dp,0,sizeof(dp));
for(i=1;i<=n;i++)
{
if(val[i]*num[i]>=sum)//判断出是否超出一半的价值。
{
for(k=val[i];k<=sum;k++)
{
dp[k]=max(dp[k],dp[k-val[i]]+val[i]);//找出最大的值,靠近sum的值。。(并且小于或等于sum)不会超过sum。
}
}
else
{
for(x=1;x<=num[i];x++)
{
for(y=sum;y>=val[i];y--)
{
dp[y]=max(dp[y],dp[y-val[i]]+val[i]);//若是小于sum。则直接遍历一遍,求出最大的值。依次增加。
}
}
}
}
printf("%d %d\n",ans-dp[sum],dp[sum]);
}
return 0;
}