【C++算法】01背包问题

问题

分析

        道题是典型的01背包问题,目的是在保证装入物品不超过背包容量的前提下,尽可能的多装入一些物品,使得背包内的物品价值最大。

       在解决问题之前,为描述方便,首先定义一些变量:Vi表示第 i 个物品的价值,Wi表示第 i 个物品的体积,定义V(i,j):当前背包容量 j,前 i 个物品最佳组合对应的价值。

下面寻找递推关系式,面对当前商品有两种可能性:

1.包的容量比该商品体积小,装不下,此时的价值与前i-1个的价值是一样的,即V(i,j)=V(i-1,j);

2.还有足够的容量可以装该商品,但装了也不一定达到当前最优价值,所以在装与不装之间选择最优的一个,即V(i,j)=max{V(i-1,j),V(i-1,j-w(i))+v(i)}。其中V(i-1,j)表示不装,V(i-1,j-w(i))+v(i) 表示装了第i个商品,背包容量减少w(i),但价值增加了v(i)。

由此可以得出递推关系式:

j<w(i)      V(i,j)=V(i-1,j)

j>=w(i)     V(i,j)=max{V(i-1,j),V(i-1,j-w(i))+v(i)}

之后就是两层for循环利用递推关系式填dp二维数组的表了

代码和运行结果

#include <iostream>
#include <vector>

// 定义物品结构体
struct Item {
    int weight;
    int value;
};

// 获取最大值
int max(int a, int b) {
    return (a > b) ? a : b;
}

// 背包问题函数
int knapsack(int capacity, const std::vector<Item>& items) {
    int n = items.size();
    std::vector<std::vector<int>> dp(n + 1, std::vector<int>(capacity + 1, 0));

    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= capacity; ++j) {
            if (items[i - 1].weight <= j) {
                dp[i][j] = max(dp[i - 1][j], items[i - 1].value + dp[i - 1][j - items[i - 1].weight]);
            }
            else {
                dp[i][j] = dp[i - 1][j];
            }
        }
    }

    // 根据 dp 数组回溯得到选择方案
    std::vector<int> chosenItems(n, 0);
    int i = n, j = capacity;
    while (i > 0 && j > 0) {
        if (dp[i][j] != dp[i - 1][j]) {
            chosenItems[i - 1] = 1;
            j -= items[i - 1].weight;
        }
        --i;
    }

    // 输出选择方案
    for (int k = 0; k < n; ++k) {
        std::cout << chosenItems[k];
    }
    std::cout << std::endl;

    return dp[n][capacity];
}

int main() {
    int n;
    std::cin >> n;

    std::vector<Item> items(n);
    for (int i = 0; i < n; ++i) {
        std::cin >> items[i].weight >> items[i].value;
    }

    int capacity;
    std::cin >> capacity;

    int maxTotalValue = knapsack(capacity, items);

    return 0;
}

01背包问题的核心就是在寻找递推关系式,寻找递推关系式的思路如下:

如果当前物品的重量Wi大于背包的容量j,则无法将该物品放入背包中,因此当前最佳组合的总价值与前i-1个物品的最佳组合总价值相同,即V(i, j) = V(i-1, j)。

如果当前物品的重量Wi小于等于背包的容量j,那么可以选择将该物品放入背包,也可以选择不放入背包,取两种情况下的总价值的较大值,即V(i, j) = max{V(i-1, j), V(i-1, j-Wi) + Vi}。其中,V(i-1, j)表示不放入当前物品时的最佳组合总价值,V(i-1, j-Wi) + Vi表示放入当前物品后的最佳组合总价值,其中背包容量减少Wi,但总价值增加Vi。

根据递推关系式,我们可以使用二维数组dp来记录子问题的最优解。通过两层循环遍历每个物品和背包容量,填充dp数组中的值,最终得到dp[n][C]即为所求的最大总价值,其中n为物品的个数,C为背包的容量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值