题意:给出价值和数量,求能分开的最近的两个总价值,例如10,20*2,30,分开就是40,40
链接:点我
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
using namespace std;
#define MOD 1000000007
const int INF=0x3f3f3f3f;
const double eps=1e-;
typedef long long ll;
#define cl(a) memset(a,0,sizeof(a))
#define ts printf("*****\n");
const int MAXN=;
int n,m,tt;
int a[MAXN],b[MAXN];
int dp[MAXN]; int nValue;
//0-1背包,代价为cost,获得的价值为weight
void ZeroOnePack(int cost,int weight)
{
for(int i=nValue;i>=cost;i--)
dp[i]=max(dp[i],dp[i-cost]+weight);
}
//完全背包,代价为cost,获得的价值为weight
void CompletePack(int cost,int weight)
{
for(int i=cost;i<=nValue;i++)
dp[i]=max(dp[i],dp[i-cost]+weight);
}
//多重背包
void MultiplePack(int cost,int weight,int amount)
{
if(cost*amount>=nValue)CompletePack(cost,weight);
else
{
int k=;
while(k<amount)
{
ZeroOnePack(k*cost,k*weight);
amount-=k;
k<<=;
}
ZeroOnePack(amount*cost,amount*weight);
}
}
int main()
{
int i,j,k;
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
#endif
while(scanf("%d",&n)!=EOF)
{
if(n<) break;
nValue=;
for(i=;i<n;i++)
{
scanf("%d%d",&a[i],&b[i]);
nValue+=a[i]*b[i];
}
cl(dp);
for(i=;i<n;i++)
{
MultiplePack(a[i],a[i],b[i]);
}
int v=nValue/;
while(dp[v]!=v) v--;
printf("%d %d\n",nValue-v,v);
}
}