题解:定义dp[i][j][k]为前i个瓶子选了j个容量为k,所以当前答案就是总水量减去j个瓶子的水量,这就转化为一个背包问题,从前i个瓶子选出j个,在容量不小于tot的情况下水的总量最多。
dp[i][j][k]=max(dp[i-1][j][k],dp[i-1][j-1][k-b[i]]+a[i]).
可以用滚动数组优化。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
int a[105],b[105],dp[105][10005],sum[105];
int main(){
int n,i,j,k,tot=0;
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d",&a[i]);
tot+=a[i];
}
for(i=1;i<=n;i++){
scanf("%d",&b[i]);
sum[i]=sum[i-1]+b[i];
}
int s=inf,t=inf;
for(i=0;i<=n;i++){
for(j=0;j<=sum[n];j++){
dp[i][j]=-inf;
}
}
dp[0][0]=0;
for(i=1;i<=n;i++){
for(j=i;j>=1;j--){
for(k=sum[i];k>=b[i];k--){
dp[j][k]=max(dp[j][k],dp[j-1][k-b[i]]+a[i]);
if(tot<=k&&dp[j][k]>=0){
if(j<s){
s=j;
t=tot-dp[j][k];
}
else if(j==s){
t=min(t,tot-dp[j][k]);
}
}
}
}
}
printf("%d %d\n",s,t);
return 0;
}