ZOJ Problem Set - 4019 Schrödinger's Knapsack(2018浙江大学校赛)
Schrödinger’s Knapsack
总结
坑点:大水题,大水题,我是个大菜逼,TLE 了好几发,发现他这个条件给的用memset太不划算了,还不如for循环,就因为这个卡了好几发,真鸡儿悲伤
题意
背包问题的变形,虽然跟背包相去甚远,但还是一个dp问题,给定一个背包容量,有两大类物品,这两大类物品,每一种物品都有固定的价值,但是体积不相同,而且放入每一个物品的增加的价值等于价值*(加入本物品后剩余的容量)
算法分析
对与每一个大类按体积进行升序排序,因为肯定优先选择体积小的物品,排序后预处理,suma[i] 代表第一类到第i个物品的体积,sumb[i] 代表到第二类物品到第i个物品的体积,dp[i][j] 代表选择 第一类物品选择i个,第二个物品选择j个的最大价值
然后进行dp,
n*m的复杂度
参考代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2000+10;
int a[maxn];
int b[maxn];
long long F[maxn][maxn];
int n,m;
long long suma[maxn],sumb[maxn];
int k1,k2,c;
int len1,len2;
void init(void)
{
len1 = len2 = 0;
scanf("%d %d %d",&k1,&k2,&c);
scanf("%d %d",&n,&m);
for(int i = 1; i <= n; ++i)
{
scanf("%d",&a[i]);
}
for(int j = 1; j <= m; ++j)
{
scanf("%d",&b[j]);
}
sort(a+1,a+n+1);
sort(b+1,b+m+1);
len1 = n,len2 = m;
for(int i = 1; i <= len1; ++i)
{
suma[i] = suma[i-1] + a[i];
if(suma[i] >= c)
{
len1 = i;
break;
}
}
for(int i = 1; i <= len2; ++i)
{
sumb[i] = sumb[i-1] + b[i];
if(sumb[i] >= c)
{
len2 = i;
break;
}
}
}
long long process(void)
{
long long ans = 0;
for(int i = 0; i <= len1; ++i)
{
for(int j = 0; j <= len2; ++j)
{
F[i][j] = 0;
long long tmp = c - suma[i] - sumb[j];
if(tmp <= 0)
continue;
if(i > 0)
F[i][j] = F[i-1][j]+k1*tmp;
if(j > 0)
F[i][j] = max(F[i][j],F[i][j-1]+k2*tmp);
ans = max(ans,F[i][j]);
}
}
return ans;
}
int main(void)
{
int T;
scanf("%d",&T);
while(T--)
{
// memset(F,0,sizeof(F));
init();
printf("%lld\n",process());
}
return 0;
}