codeforces 730J
题目链接(luogu)https://www.luogu.org/problemnew/show/CF730J
首先讲这道题分析一下。杯子分为倒与不倒,01背包。
确立背包内容:k易得,在众多抉择中选出最佳的决策。
本题有两种思路,一种是用水做dp,一种是用体积做dp,只说第一种(空间更小)。
目的是用k个杯子并让其中的水最多。(t最小)
首先决定为dp_i_j_k,指当前已经判断到i了且选用了j个杯子,其中有k份水.
所以可以推到选或不选
那么dp[i][j][k]=>dp[i-1][j][k]或dp[i-1][j-1][k-bot[i].le]+bot[i].vi)两个决策。
于是递推即可。
可以知道不同水量下的体积。
只用让这体积>=总的水量
所以逆推水量,找到体积合适的时候,记住循环的标记(i)
再用水的体积减去该数即可。
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
struct bos
{
int le,vi;
};
bool cmp(bos a,bos b)
{
return a.vi>b.vi;
}
bos bot[105];
int dp[105][10005];
int main()
{
int n,sum=0;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>bot[i].le;
sum+=bot[i].le;
}
for(int i=1;i<=n;i++)
{
cin>>bot[i].vi;
}
int diss=0,flag=0;
sort(bot+1,bot+n+1,cmp);
for(int i=1;i<=n;i++)
{
diss+=bot[i].vi;
if(diss>=sum)
{
flag=i;
break;
}
}
memset(dp,0xff,sizeof(dp));
dp[0][0]=0;
for(int i=1;i<=n;i++)
for(int j=i;j>=1;j--)
for(int k=sum;k>=bot[i].le;k--)
{
if(dp[j-1][k-bot[i].le]!=-1)
dp[j][k]=max(dp[j][k],dp[j-1][k-bot[i].le]+bot[i].vi);
}
int two=0;
for(int i=sum;i>=0;i--)
{
if(dp[flag][i]>=sum)
{
two=sum-i;
break;
}
}
cout<<flag<<" "<<two;
}