动态规划 —— 01背包问题

01背包问题

有n个重量和价值分别为wi,vi的物品。
从这些物品中挑选出总重量不超过W的物品,
求所有挑选方案中价值总和的最大值。

针对每个物品是否放入背包进行搜索

#include <iostream>

#define MAX_N 100

using namespace std;

int n, W;
int w[MAX_N], v[MAX_N];

int rec(int i, int j) {      //从第i个物品开始挑选总重量小于j的部分
    int res;

    if (i == n) res = 0;    //已经没有剩余物品了
    else if (j < w[i]) res = rec(i + 1, j);     //无法挑选这个物品
    else res = max(rec(i + 1, j), rec(i + 1, j - w[i]) + v[i]);      //挑选和不挑选的两种情况都尝试一下

    return res;
}

int main() {
    cin >> n;
    for (int i = 0; i < n; i++)
        cin >> w[i] >> v[i];
    cin >> W;
    cout << rec(0, W) << endl;
    return 0;

这种方法的搜索深度是n,而且每一层的搜索都需要两次分支,最坏就需要O(2n)的时间,当n比较大的时候就没办法解了。

为了避免产生重复计算采用记忆化搜索

#include <iostream>
#include <cstring>

#define MAX_N 100
#define MAX_W 100

using namespace std;

int n, W;
int w[MAX_N], v[MAX_N];
int dp[MAX_N + 1][MAX_W + 1];

int rec(int i, int j) {
    if (dp[i][j]) return dp[i][j];  //已经计算过的话直接使用之前的结果

    int res;

    if (i == n) res = 0;
    else if (j < w[i]) res = rec(i + 1, j);
    else res = max(rec(i + 1, j), rec(i + 1, j - w[i]) + v[i]);

    return dp[i][j] = res;
}

int main() {
    cin >> n;
    for (int i = 0; i < n; i++)
        cin >> w[i] >> v[i];
    cin >> W;
    memset(dp, 0, sizeof(dp));
    cout << rec(0, W);
    return 0;
}

对于同样的参数,只会在被调用到时执行递归部分,第二次之后都会直接返回。参数的组合不过nW种,而函数内只调用2次递归,所以只需要O(nW)的复杂度就能解决。

DP数组

记dp[i][j]根据rec的定义,从第i个物品开始挑选总重小于j时总价值的最大值。

递推公式:
dp[n][j]=0
if(j<w[i]) dp[i][j]=dp[i+1][j]
else dp[i][j]=max(rec(i+1,j),rec(i+1,j-w[i])+v[i])

#include <iostream>

#define MAX_N 100
#define MAX_W 100

using namespace std;

int n, W;
int w[MAX_N], v[MAX_N];
int dp[MAX_N + 1][MAX_W + 1];

int main() {
    cin >> n;
    for (int i = 0; i < n; i++)
        cin >> w[i] >> v[i];
    cin >> W;
    for (int i = n - 1; i > -1; i--) {
        for (int j = 0; j < W + 1; j++) {
            if (j < w[i]) dp[i][j] = dp[i + 1][j];
            else dp[i][j] = max(dp[i + 1][j], dp[i + 1][j - w[i]] + v[i]);
        }
    }
    cout << dp[0][W];
    return 0;
}
原文地址:https://www.cnblogs.com/AlexKing007/p/12338305.html