刚看到这题的时候,想都没多想,就开始暴力,结果runtime error,我想那应该是数组越界了。因为我暴力的解法的空间复杂度是nk[1]*nk[2]*、、、不用多想也知道是越界了,可是我好久后才发现,真水~
{
int f[n];
int cash, N, nk[11], dk[11];
int i, j, p, k;
while(scanf("%d %d",&cash, &N) != EOF)
{
memset(f, 0, n*sizeof(int));
for(i = 1; i <= N; i++)
scanf("%d%d", &nk[i], &dk[i]);
for(p = 1; p <= N; p++)
{
for(k = 1; k <= nk[p]; k*=2)
{
for(i = cash; i >= k*dk[p]; i--)
{
f[i] = max(f[i], f[i-k*dk[p]]+k*dk[p]);
}
nk[p] -= k;
}
k = nk[p];
for(i = cash; i >= k*dk[p]; i--)
{
f[i] = max(f[i], f[i-k*dk[p]]+k*dk[p]);
}
}
printf("%d\n", f[cash]);
}
}
这是个多重背包问题,第二次我把它转化为01背包问题,结果TLE. 因为我把它转化为N*nk[i]张钞票,cash的最大值为100000,这种做法显然会超时。不过我的体会也挺深的,就是01背包的思想很重要,其他背包问题可以通过一定的方式转化为01背包问题,加上一定的优化,就能达成我们的目的。优化后的01背包的状态转移方程为:
for i=1..N
for v=V..0
f[v]=max{f[v],f[v-c[i]]+w[i]};
第三次重敲代码,我是用二进制思想来进行优化的。就是把nk[i]件物品分成2^0,2^1,、、、,2^(k-1),nk[i]-2^(k-1),这些项的和为nk[i],即可以通过这些来构成0~nk[i]期间的任一一种情况。这是一个很好的优化,时间复杂度降到(V*Σlog n[i]),对于这题来说已经够优化了。我提交的结果时间是76MS.多重背包转化后的伪代码如下:
k = 1;
while(k <= nk[i])
{
zeroone(); / / 这是01背包;
nk[i] -= k;
k *=2;
}
k = nk[i];
zeroone();
pku1276的代码
code:
#include<string.h>
#include<stdio.h>
#define n 100005
int max(int a, int b)
{
return a > b ? a : b;
}
{
int f[n];
int cash, N, nk[11], dk[11];
int i, j, p, k;
while(scanf("%d %d",&cash, &N) != EOF)
{
memset(f, 0, n*sizeof(int));
for(i = 1; i <= N; i++)
scanf("%d%d", &nk[i], &dk[i]);
for(p = 1; p <= N; p++)
{
for(k = 1; k <= nk[p]; k*=2)
{
for(i = cash; i >= k*dk[p]; i--)
{
f[i] = max(f[i], f[i-k*dk[p]]+k*dk[p]);
}
nk[p] -= k;
}
k = nk[p];
for(i = cash; i >= k*dk[p]; i--)
{
f[i] = max(f[i], f[i-k*dk[p]]+k*dk[p]);
}
}
printf("%d\n", f[cash]);
}
}