背包问题

 

  最近在洛谷上写了几个背包的板子题,总结一下。

 

  1. 01背包  

  01背包问题一般是:告诉你有N件物品和一个容量为V的背包。第i件物品的重量是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。

  对于每一件物品我们可以选择取还是不取。

  我们可以定义一个二维数组 f[i][j] 来表示对前i个物品,你选择取或不取后,这个容量为V的背包中最大的价值为多少。

  对于第i个物品,当我们选择取的时候:f[i][j] = f[i-1][j-w[i]]+c[i] ;(显然此时 j 的范围为 w[i]~V )

  当我们选择不取的时候:f[i][j] = f[i-1][j];

  

for(int i = 1; i <= N; i++)
    {
        for(int j = 0; j <= V; j++){
            if (V < w[i]){
                f[i][j] = f[i-1][j];
            }else {
                f[i][j] = max(f[i-1][j],f[i-1][j-w[i]]+c[i]);
            }
        }
    }

 

  显然,我们能把数组可以将f缩减成一维数组,从而达到优化空间的目的,状态转移方程转换为:

     f[j] = max(f[j],f[j-w[i]]+c[i])

 

 

for(int i = 1; i <= N; i++)
    {
        for(int j = V; j >= w[i]; j--){
            f[j] = max(f[j],f[j-w[i]]+c[i]);
        }
    }

 

 

 

例题:P2871 [USACO07DEC]手链Charm Bracelet

 

  2. 完全背包     

   完全背包问题一般是:告诉你有N种物品和一个容量为V的背包,每种物品不限数量。第i件物品的重量是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。

  和01背包类似,我们对于每种物品可以不取、取一件、甚至取多件,只要容量够。

 

for(int i = 1; i <= N; i++)
        for(int j=w[i]; j<=V; j++)
            f[j]=max(f[j-w[i]]+c[i], f[j]);

 

 

 

例题:P2722 总分 Score Inflation

 

  3. 多重背包     

  多重背包问题一般是:告诉你有N种物品和一个容量为V的背包,每种物品数量为num[i]。第i件物品的重量是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。

  我们可以把它转化为01背包问题。

  朴素算法:

 

for (int i = 1; i <= N; i++)
        for (int j = V; j >= 0; j--)
            for (int k = 0; k <= num[i]; k++)
            {
                if (j-k*w[i]<0) break;
                f[j] = max(f[j],f[j-k*w[i]]+k*c[i]);
            }

 

  进行二进制优化:

  先将num[i]个物品分成多个物品,它们的重量方便为 c ={ k*c[i] | k = 1  2  4 8 ...,如果数量有剩余则剩下的算一个物体}

  然后按01背包做。

    int cnt = 0;
    for (int i = 0; i < N; i++){
        scanf("%d%d%d",&wi,&ci,&numi);
        for (int j = 1; j <= numi; j<<=1){
            w[cnt] = j*wi;
            c[cnt] = j*ci;
            numi-=j;
            cnt++;
        }
        if (numi){
            w[cnt] = numi*wi;
            c[cnt] = numi*ci;
            cnt++;
        }
    }
    for (int i = 0; i < cnt; i++){
        for (int j = V; j >= w[i]; j--){
            f[j] = max(f[j],f[j-w[i]]+c[i]);
        }
    }

 

  例题:51nod 1086背包问题v2

 

 

 

 

 

  

 

posted @ 2018-08-24 09:37  19呀  阅读(171)  评论(0编辑  收藏  举报