动态规划--背包问题

题目大意:

有 $n$ 个物体 第 $i$ 个物体的体积为 $wi$ 价值为 $vi$ 背包容积为 $W$ 求所有挑选方案中价值总和的最大值

解法1:

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

时间复杂度:$O(2^n)$

代码:

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e5 + 10;
int n, W;
int w[maxn], v[maxn];

int rec(int i, int 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;
}

void solve() {
    printf("%d
", rec(0, W));
}

int main() {
    scanf("%d%d", &n, &W);
    for(int i = 0; i < n; i ++)
        scanf("%d%d", &w[i], &v[i]);

    solve();
    return 0;
}

解法2:

记忆化搜索,把第一次计算结果存到 $dp$ 数组中,第二次之后如果有同样的 $i, j$ 直接返回

时间复杂度:$O(n * W)$

代码:

#include <bits/stdc++.h>
using namespace std;

int n, W;
int w[11111], v[11111];
int dp[11111][11111];

int rec(int i, int j) {
    if(dp[i][j] >= 0)
        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;
}

void solve() {
    memset(dp, -1, sizeof(dp));
    printf("%d
", rec(0, W));
}

int main() {
    scanf("%d%d", &n, &W);
    for(int i = 0; i < n; i ++)
        scanf("%d%d", &w[i], &v[i]);

    solve();
    return 0;
}

 解法3:

dfs

时间复杂度:$O(2^n)$

代码:

#include <bits/stdc++.h>
using namespace std;

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

int dfs(int i, int j, int sum) {
    int res;
    if(i == n)
        res = sum;
    else if(j < w[i])
        res = dfs(i + 1, j, sum);
    else
        res = max(dfs(i + 1, j, sum), dfs(i + 1, j - w[i], sum + v[i]));

    return res;
}

int main() {
    scanf("%d%d", &n, &W);
    for(int i = 0; i < n; i ++)
        scanf("%d%d", &w[i], &v[i]);

    int num = dfs(0, W, 0);
    printf("%d
", num);
    return 0;
}

解法4:

动态规划 不写递归函数,直接用递推式把各项的值计算出来(如果多组输入 $dp$ 需要初始化)

时间复杂度:$O(n * W)$

代码1:

#include <bits/stdc++.h>
using namespace std;

int n, W;
int w[11111], v[11111];
int dp[11111][11111];

void solve() {
    for(int i = n - 1; i >= 0; i --) {
        for(int j = 0; j <= W; 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]);
        }
    }
    printf("%d
", dp[0][W]);
}

int main() {
    scanf("%d%d", &n, &W);
    for(int i = 0; i < n; i ++)
        scanf("%d%d", &w[i], &v[i]);

    solve();
    return 0;
}

 代码2:

#include <bits/stdc++.h>
using namespace std;

int n, W;
int w[11111], v[11111];
int dp[11111][11111];

void solve() {
    for(int i = 0; i < n; i ++) {
        for(int j = 0; j <= W; j ++) {
            if(j < w[i])
                dp[i + 1][j] = dp[i][j];
            else
                dp[i + 1][j] = max(dp[i][j], dp[i][j - w[i]] + v[i]);
        }
    }
    printf("%d
", dp[n][W]);
}

int main() {
    scanf("%d%d", &n, &W);
    for(int i = 0; i < n; i ++)
        scanf("%d%d", &w[i], &v[i]);

    solve();
    return 0;
}

 代码3:

#include <bits/stdc++.h>
using namespace std;

int n, W;
int w[11111], v[11111];
int dp[11111][11111];

void solve() {
    for(int i = 0; i < n; i ++) {
        for(int j = 0; j <= W; j ++) {
            dp[i + 1][j] = max(dp[i][j], dp[i + 1][j]);
            if(j + w[i] <= W)
                dp[i + 1][j + w[i]] = max(dp[i + 1][j + w[i]], dp[i][j] + v[i]);
        }
    }
    printf("%d
", dp[n][W]);
}

int main() {
    scanf("%d%d", &n, &W);
    for(int i = 0; i < n; i ++)
        scanf("%d%d", &w[i], &v[i]);

    solve();
    return 0;
}

  

原文地址:https://www.cnblogs.com/zlrrrr/p/9562981.html