题目:给两个序列,两个序列的系数分别为k1,k2,有一个背包容量为c,从两个序列里面取数(这个数相当于放入物品的体积)放入到背包中,使得背包里面装的价值最大
条件:1,每次放进背包里面的价值=背包剩余的体积*放入物品对应序列的系数
输入:输入t组数据
k1,k2,c(1<=k1,k2,c<=10的7次方)
输入两个序列的长度n,m(1<=n,m<=2000)
输入两个序列中每个物品的体积(1<=每个体积<=10的7次方)
输出:背包的最大价值
思路:是一道dp问题,每次选择的时候肯定是剩余的体积越大越好,那么选取的物品肯定是体积越小越好,不能一直对比取每次最小的体积,因为剩余的体积会变。先对每个序列的体积进行排序,每个序列的排序后的前缀和是一定要算的。状态转移方程:dp[i][j]=max(dp[i][j-1]+k2*(cn-suma[i]-sumb[j]),dp[i-1][j]+k1*(cn-suma[i]-sumb[j]))。
代码:
#include <iostream>
#include <map>
#include <queue>
#include <stack>
#include <vector>
#include <cstdio>
#include <string>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn=2005;
int a[maxn+1],b[maxn+1];
long long int suma[maxn+1],sumb[maxn+1];//前缀和
long long int dp[maxn+1][maxn+1];//dp
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int k1,k2,cn;
scanf("%d%d%d",&k1,&k2,&cn);
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=m;i++)
scanf("%d",&b[i]);
sort(a+1,a+n+1);
sort(b+1,b+m+1);
sumb[0]=0;
suma[0]=0;
long long int ans=0;
for(int i=1;i<=n;i++)//计算前缀和
{
suma[i]=suma[i-1]+a[i];
}
for(int i=1;i<=m;i++)
{
sumb[i]=sumb[i-1]+b[i];
}
dp[0][0]=0;
for(int i=1;i<=m;i++)//先把没有选其它序列的前缀和时的dp写出来
{
dp[0][i]=dp[0][i-1]+(cn-sumb[i])*k2;
ans=max(ans,dp[0][i]);
}
for(int i=1;i<=n;i++)
{
dp[i][0]=dp[i-1][0]+(cn-suma[i])*k1;
ans=max(ans,dp[i][0]);
}
for(int i=1;i<=n;i++)//开始dp
{
for(int j=1;j<=m;j++)
{
if(suma[i]+sumb[j]<=cn)
{
dp[i][j]=max(dp[i][j-1]+k2*(cn-suma[i]-sumb[j]),dp[i-1][j]+k1*(cn-suma[i]-sumb[j]));
ans=max(ans,dp[i][j]);
}
}
}
printf("%lld\n",ans);
}
return 0;
}
总结:1,回顾了一下dp 2,排位赛的时候没有看这题有点亏,读英文题的不够耐心,每次比赛都没有把所有的题目都看过一遍