01背包

0/1背包二维形式

二维数组 f[][] 被用作动态规划的辅助数组,它的作用是存储在不同的背包容量和不同的物品选取情况下所能达到的最大总价值。

具体来说,f[i][j] 表示在前 i 个物品中选取,并且背包容量限制为 j 时所能达到的最大总价值。

在动态规划的过程中,f[i][j] 的计算依赖于前一行 f[i - 1][j] 和可能的另一项 f[i - 1][j - v[i]] + w[i]。其中 f[i - 1][j] 表示不选择当前物品 i 的情况下的最大价值,而 f[i - 1][j - v[i]] + w[i] 表示选择当前物品 i 后的最大价值。通过比较这两种情况的价值,更新 f[i][j] 为较大的那个值,从而不断地填充 f[][] 数组,直到计算得到 f[n][m],即前 n 个物品在背包容量为 m 时的最大总价值。

因此,f[][] 数组在这里扮演了记录子问题最优解的角色,通过填充这个数组,最终可以得到原问题的最优解。

#include<iostream>
#include<algorithm>
using namespace std;

const int N = 1010; // 定义常量 N,值为 1010
int v[N], w[N]; // 声明数组 v 和 w,用于存储物品的价值和重量
int f[N][N]; // 声明二维数组 f,用于动态规划

int main()
{
    int n, m;
    cin >> n >> m; // 读取物品数量 n 和最大承重 m

    // 输入每个物品的价值和重量
    for (int i = 1; i <= n; i++)
        cin >> v[i] >> w[i];

    // 动态规划计算最大价值
    for (int i = 1; i <= n; i++) // 对于每个物品
        for (int j = 1; j <= m; j++) // 对于每种可能的重量
        {
            f[i][j] = f[i - 1][j]; // 默认情况下,不选择当前物品 i

            // 如果当前重量可以容纳物品 i,则考虑选择物品 i 的情况
            if (j >= v[i])
                f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i]);
        }

    cout << f[n][m] << endl; // 输出最大价值
    return 0;
}

0/1背包一维形式

将二维形式的动态规划转换为一维形式的关键在于重新设计状态转移方程,并且利用一维数组来存储中间状态。下面是从二维形式到一维形式的转换步骤:

  1. 重新定义状态

    • 在二维形式中,状态 f[i][j] 表示在前 i 个物品中选取,并且背包容量限制为 j 时所能达到的最大总价值。
    • 在一维形式中,我们需要重新定义状态,令 f[j] 表示背包在容量为 j 时所能达到的最大总价值。
  2. 更新状态转移方程

    • 在二维形式中,状态转移方程为:f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i])
    • 我们需要重新设计状态转移方程,以便在一维数组中更新 f[j]。观察二维形式的转移方程,可以发现 f[i][j] 的更新只与 f[i - 1][j]f[i - 1][j - v[i]] 相关。因此,我们可以将状态转移方程改写为:f[j] = max(f[j], f[j - v[i]] + w[i])
  3. 适当修改遍历顺序

    • 在二维形式中,我们使用了两个循环,其中外循环遍历物品,内循环遍历背包容量。
    • 在一维形式中,我们只需要一个循环来遍历物品,并且通过逆序遍历背包容量,以确保每次更新 f[j] 时所需的 f[j - v[i]] 是上一轮循环的值。
    for (int i = 1; i <= n; i++) {
        for (int j = m; j >= v[i]; j--) {
            f[j] = max(f[j], f[j - v[i]] + w[i]);
        }
    }
    
    

    在这段代码中,我们只使用了一个循环来遍历物品,通过逆序遍历背包容量,从而确保每次更新 f[j] 时所需的 f[j - v[i]] 是上一轮循环的值。

#include<iostream>
#include<algorithm>
using namespace std;

const int N = 1010; // 定义常量 N,值为 1010
int v[N], w[N]; // 声明数组 v 和 w,用于存储物品的价值和重量
int f[N]; // 声明数组 f,用于存储背包在不同容量下的最大总价值

int main()
{
    int n, m;
    cin >> n >> m; // 读取物品数量 n 和最大承重 m

    // 输入每个物品的价值和重量
    for (int i = 1; i <= n; i++)
        cin >> v[i] >> w[i];

    // 动态规划计算最大总价值
    for (int i = 1; i <= n; i++) // 对于每个物品
        for (int j = m; j >= v[i]; j--) // 对于每种可能的背包容量(逆序遍历)
        {
            // 考虑选取当前物品 i 的情况,更新背包容量为 j 时的最大总价值
            f[j] = max(f[j], f[j - v[i]] + w[i]);
        }

    cout << f[m] << endl; // 输出背包容量为 m 时的最大总价值
    return 0;
}

posted @ 2024-03-24 21:14  W_K_KAI  阅读(35)  评论(0)    收藏  举报