动态规划5:01背包问题和完全背包问题不同空间复杂度的解法

01背包问题

1.空间复杂度O(V) 时间复杂度O(V)

/*
 * 01背包问题
 * 件数 5 最大重量 8
 * 3 5 1 2 2
 * 4 5 2 1 3
 * */
#include "cstdio"
#include "cstring"
#include "algorithm"
#include "vector"

using namespace std;
const int maxn = 100;//物品最大件数
const int maxv = 1000;//容量上限
int w[maxn], c[maxn], dp[maxv];

/*
 * w[] 物品重量
 * c[] 物品价值
 * dp[v] 容量为v时物品最大价值

 * */

int main() {
    int n, V;//件数 总容量
    scanf("%d%d", &n, &V);
    for (int i = 1; i <= n; i++) {
        //物品容量
        scanf("%d", &w[i]);

    }
    for (int i = 1; i <= n; i++) {
        //物品价值
        scanf("%d", &c[i]);

    }
    //边界
    //使用滚动数组 倒序查找
    for (int v = 0; v <= V; v++)
        dp[v] = 0;
    //求解
    for (int i = 1; i <= n; i++) {
        printf("\n");
        for (int v = V; v >= w[i]; v--) {
            //状态转移方程
            //放入或不放入第i件物品的价值
            printf("剩余v: %d  ", v);
            printf("w[%d]: %d  ", i, w[i]);
            printf("dp[%d]: %d  dp[%d]+c[%d]: %d  ", v, dp[v], v - w[i], i, dp[v - w[i]] + c[i]);
            dp[v] = max(dp[v], dp[v - w[i]] + c[i]);
            printf("新dp[%d]: %d  \n", v, dp[v]);
        }
    }
    //寻找dp[] 最大值就是答案
    int max = 0, loc = 0;
    for (int i = 0; i <= V; i++) {
        if (dp[i] > max) {
            max = dp[i];
        }

    }
    printf("max: %d\n", max);

    return 0;

}
/*
5 8
3 5 1 2 2
4 5 2 1 3
 */

测试结果:
在这里插入图片描述

2.空间复杂度O(nV) 时间复杂度O(nV)

/*
 * 01背包问题
 * 件数 5 最大重量 8
 * 3 5 1 2 2
 * 4 5 2 1 3
 * */
#include "cstdio"
#include "cstring"
#include "algorithm"
#include "vector"

using namespace std;
const int maxn = 100;//物品最大件数
const int maxv = 1000;//容量上限
int w[maxn], c[maxn], dp[maxn][maxv];
bool flag[maxn] = {0};

/*
 * w[] 物品重量
 * c[] 物品价值
 * dp[i][v] 前i件产品装入容量v时最大价值
 * flag[] 最优解
 * */

int main() {
    int n, V;//件数 总容量
    scanf("%d%d", &n, &V);
    for (int i = 1; i <= n; i++) {
        //物品容量
        scanf("%d", &w[i]);

    }
    for (int i = 1; i <= n; i++) {
        //物品价值
        scanf("%d", &c[i]);

    }
    //边界
    for (int v = 0; v <= V; v++)
        dp[0][v] = 0;
    //求解
    for (int i = 1; i <= n; i++) {
        for (int v = w[i]; v <= V; v++) {
            //状态转移方程
            //放入或不放入第i件物品的价值

            dp[i][v] = max(dp[i - 1][v], dp[i - 1][v - w[i]] + c[i]);
        }
    }
    //寻找dp[] 最大值就是答案
    int max = 0, loc = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= V; j++) {
            if (dp[i][j] > max) {
                max = dp[i][j];
                loc = j;
            }
        }
    }
    int c = loc;
    for (int i = 1; i < n; i++) {

        if (dp[i][c] == dp[i + 1][c]) {
            flag[i] = 0;
        } else {
            flag[i] = 1;
            c = c - w[i];
        }

    }
    flag[n] = dp[n][c] ? 1 : 0;


    for (int i = 1; i <= n; i++) {
        //方案
        printf("%d ", flag[i]);
    }

    printf("\n");
    printf("max: %d\n", max);
    return 0;

}
/*
5 8
3 5 1 2 2
4 5 2 1 3

 */

测试结果:
在这里插入图片描述
完全背包问题

1.空间复杂度O(V) 时间复杂度O(V)

与01背包问题相比,状态转移方程完全相同,物品件数变成无限多,不再是放入和不放入两种状态,v的枚举变成正向枚举

/*
 * 完全背包问题——每种物品件数无限
 * 件数 5 最大重量 8
 * 3 5 1 2 2
 * 4 5 2 1 3
 * */
#include "cstdio"
#include "cstring"
#include "algorithm"
#include "vector"

using namespace std;
const int maxn = 100;//物品最大件数
const int maxv = 1000;//容量上限
int w[maxn], c[maxn], dp[maxv];

/*
 * w[] 物品重量
 * c[] 物品价值
 * dp[v] 容量为v时物品最大价值

 * */

int main() {
    int n, V;//件数 总容量
    scanf("%d%d", &n, &V);
    for (int i = 1; i <= n; i++) {
        //物品容量
        scanf("%d", &w[i]);

    }
    for (int i = 1; i <= n; i++) {
        //物品价值
        scanf("%d", &c[i]);

    }
    //边界

    for (int v = 0; v <= V; v++)
        dp[v] = 0;
    //求解
    //使用滚动数组 正序枚举(倒序为01问题)
    for (int i = 1; i <= n; i++) {
        for (int v = w[i]; v <= V; v++) {
            //状态转移方程
            //放入或不放入第i件物品的价值
            dp[v] = max(dp[v], dp[v - w[i]] + c[i]);
        }
    }
    //寻找dp[] 最大值就是答案
    int max = 0, loc = 0;
    for (int i = 0; i <= V; i++) {
        if (dp[i] > max) {
            max = dp[i];
        }

    }

    printf("max: %d\n", max);

    return 0;

}
/*
5 8
3 5 1 2 2
4 5 2 1 3
 */

测试结果:
在这里插入图片描述

2.空间复杂度O(nV) 时间复杂度O(nV)

每种物品可以放入任意件,01背包问题中,如果选择放入第i件产品,状态要转移到dp[i - 1][v - w[i]] 而完全背包问题要转移到 dp[i ][v - w[i]] + c[i]

/*
 * 完全背包问题——每种物品件数无限
 * 件数 5 最大重量 8
 * 3 5 1 2 2
 * 4 5 2 1 3
 * */

#include "cstdio"
#include "cstring"
#include "algorithm"
#include "vector"

using namespace std;
const int maxn = 100;//物品最大件数
const int maxv = 1000;//容量上限
int w[maxn], c[maxn], dp[maxn][maxv];
int flag[maxn] = {0};

/*
 * w[] 物品重量
 * c[] 物品价值
 * dp[i][v] 前i件产品装入容量v时最大价值
 * flag[] 最优解
 * */

int main() {
    int n, V;//件数 总容量
    scanf("%d%d", &n, &V);
    for (int i = 1; i <= n; i++) {
        //物品容量
        scanf("%d", &w[i]);

    }
    for (int i = 1; i <= n; i++) {
        //物品价值
        scanf("%d", &c[i]);

    }
    //边界
    for (int v = 0; v <= V; v++)
        dp[0][v] = 0;
    //求解
    for (int i = 1; i <= n; i++) {
        for (int v = w[i]; v <= V; v++) {
            //状态转移方程
            //放入或不放入第i件物品的价值

            dp[i][v] = max(dp[i - 1][v], dp[i][v - w[i]] + c[i]);
        }
    }
    //寻找dp[] 最大值就是答案
    int max = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= V; j++) {
            if (dp[i][j] > max) {
                max = dp[i][j];
            }
        }
    }
    printf("max: %d\n", max);
    return 0;

}
/*
5 8
3 5 1 2 2
4 5 2 1 3

 */

测试结果:
在这里插入图片描述

发布了51 篇原创文章 · 获赞 1 · 访问量 6044

猜你喜欢

转载自blog.csdn.net/qq_39827677/article/details/104608007