• 背包问题整理


    背包问题

    给定一组物品,每种物品都有自己的重量和价值,现有一个背包,能承受的重量有限,在受限制的重量下,取若干物品,使得总价值最大。这一类问题,被称为背包问题。

    01背包(物品个数为1)

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

    时间上是两重循环,时间复杂度为O(NV)。空间是二维的,空间复杂度也为O(NV)。

    for (int i = 1; i <= n; ++i)
        for (int j = v; j >= c[i]; --j) {
            dp[j] = max(dp[j - c[i]] + w[i], dp[j]);
        }

    这个做法空间复杂度也为O(V)。

    多重背包(物品个数有限)

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

    这一份代码和01背包相比,不再有else部分了,因为,k = 0的时候dp[i][j] = max(dp[i - 1][j], dp[i][j]), 相当于01背包的else部分。

     空间优化

    既然多重背包的可以转换成01背包,那么我们必然也可以像01背包那样优化空间复杂度。还是按照从大到小的顺序枚举背包体积。

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

    完全背包(物品个数无限)

    解析

    虽然物品个数是无限的,但是实际上,由于背包容量有上限,每个物品最多选取的个数也是有限制的,这样可以转换成多重背包问题,进而可以转换成01背包问题。

    可以用多重背包的思想来解决完全背包。

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

    for (int i = 1; i <= n; i++) {
        for (int j = 0; j <= v; j++) {
            if (j >= c[i]) {
                dp[i][j] = max(dp[i][j - c[i]] + w[i], dp[i - 1][j]);
            } else {
                dp[i][j] = dp[i - 1][j];
            }
        }
    }

    这样我们的的算法时间复杂度O(NV),空间复杂度O(NV)。

    不难发现,我们也可以把空间复杂度优化下来,优化成O(V)。

    for (int i = 1; i <= n; i++) {
        for (int j = c[i]; j <= v; j++) {
            dp[j] = max(dp[j - c[i]] + w[i], dp[j]);
        }
    }

    与 01 背包相比,完全背包只是第二重循环的顺序发生了翻转。

    多重背包的二进制优化

     1 #include <iostream>
     2 using namespace std;
     3 int n[110], c[110], w[110];
     4 int nc[1000], nw[1000];
     5 int dp[5010];
     6 int main() {
     7     int N, V;
     8     cin >> N >> V;
     9     for (int i = 1; i <= N; ++i) {
    10         cin >> w[i] >> c[i] >> n[i];
    11     }
    12     int ncnt = 0;
    13     // 二进制拆分
    14     for (int i = 1; i <= N; ++i) {
    15         int k;
    16         // 找到最大的 k
    17         for (k = 1; n[i] - (1 << k) + 1 > 0; ++k) {
    18             nc[ncnt] = (1 << (k - 1)) * c[i];
    19             nw[ncnt] = (1 << (k - 1)) * w[i];
    20             ++ncnt;
    21         }
    22         --k;
    23         // 最后一组
    24         nc[ncnt] = (n[i] - (1 << k) + 1) * c[i];
    25         nw[ncnt] = (n[i] - (1 << k) + 1) * w[i];
    26         ++ncnt;
    27     }
    28     // 01 背包
    29     for (int i = 0; i < ncnt; ++i) {
    30         for (int j = V; j >= nc[i]; --j) {
    31             dp[j] = max(dp[j], dp[j - nc[i]] + nw[i]);
    32         }
    33     }
    34     cout << dp[V] << endl;
    35     return 0;
    36 }
    for (int i = 1; i <= n; i++)
            {
                //核心代码
                for (int j = 1; num[i] > j; j <<= 1)//注意j用到二进制位移
                {
                    sale[++count] = sale[i] * j;
                    wei[count] = wei[i] * j;
                    num[i] -= j;
                }
                wei[i] = wei[i] * num[i];
                sale[i] = sale[i] * num[i];
            }

    -

  • 相关阅读:
    《剑指offer》JavaScript版(4-6题)
    HDU 4906 Our happy ending(2014 Multi-University Training Contest 4)
    POJ 1436 Horizontally Visible Segments
    FOJ 2105 Digits Count
    HDU 4890 One to Four(2014 Multi-University Training Contest 3)
    HDU 4888 Redraw Beautiful Drawings(2014 Multi-University Training Contest 3)
    HDU 4893 Wow! Such Sequence!(2014 Multi-University Training Contest 3)
    POJ 3225 Help with Intervals
    HDU 1698 Just a Hook
    POJ 2886 Who Gets the Most Candies?
  • 原文地址:https://www.cnblogs.com/jiamian/p/12209162.html
Copyright © 2020-2023  润新知