(博客搬迁啦)pku1276多重背包问题(http://poj.org/problem?id=1276)

刚看到这题的时候,想都没多想,就开始暴力,结果runtime error,我想那应该是数组越界了。因为我暴力的解法的空间复杂度是nk[1]*nk[2]*、、、不用多想也知道是越界了,可是我好久后才发现,真水~

这是个多重背包问题,第二次我把它转化为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 main()
{
 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]);
   }
}

你可能感兴趣的:((博客搬迁啦)pku1276多重背包问题(http://poj.org/problem?id=1276))