01背包问题—题解

本文探讨了经典的背包问题,通过两种不同的方法——递归搜索和动态规划来解决该问题。介绍了如何利用这些方法找到背包能够携带的最大价值及相应的物品组合。
 背包问题
有n个物品,每个物品的重量为weight[i],每个物品的价值为value[i]。现在有一个背包,它所能容纳的重量为total,问:
当你面对这么多有价值的物品时,你的背包所能带走的最大价值是多少?
程序输入输出格式要求:
程序输入3行:
第一行是物品总数n, 第2行是每个物品的重量,第3行是每个物品的价值,第3行是背包的容量
程序输出2行:
第1行是背包所能带走的最大价值,第2行是装入最大价值时背包中的物品的序号(只需输出一个最优解即可)
例如:
用户输入:
5
2,2,6,5,4
6,3,5,4,6
10
则程序输出:
15

1,2,5


解题思路:  

1. 递归搜索。

2. 动态规划   (网上有很多好的资源)

3. 完全背包、多重背包也是一样的原理。不再解释。


源代码: 1.递归搜索

public class Main
{
static int n = 0;     // 物品的数目
static int weight[];  // 物品的重量
static int value[];   // 物品的价值

static int max = 0;   // 物品的最大价值
static int table[] = new int[100001];   // 此时物品的摆放
static int index = 0; // 物品标记
public static void main(String[] args)
  {
       Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        weight = new int [n];
        value = new int [n];
       for (int i = 0; i < n; i++) weight[i] = sc.nextInt();
       for (int i = 0; i < n; i++) value[i] = sc.nextInt();
       int total = sc.nextInt();
       sc.close();
       
       int nums[] = new int [n];   // 暂时放入物品的编号
       
       dfs(0, nums, 0, total);  // 深度搜索
       
       System.out.println(max);
       for (int i = 0; i < index; i++)
       {
      System.out.print((table[i]+1) + " ");
       }
       System.out.println();
}

private static void dfs(int num, int[] nums, int index, int total)
{
         if (num >= n)  // 没有物品搜索了。
         {
        check(nums, index);
        return;   
         }
         
         if (weight[num] > total) // 超重 return 
         {
        dfs(num+1, nums, index, total);  return ;
         }


          // 装
          nums[index++] = num;  
         dfs(num+1, nums, index, total-weight[num]);
         // 不装
          index--;
         dfs(num+1, nums, index, total);
}


private static void check(int[] nums, int index2)
{
int m = 0;
        for (int i = 0; i < index2; i++)
        { 
        m += value[nums[i]];
        }
        if (m > max)
        {
        max = m;
        // 拷贝数组
        index = index2;
        for (int i = 0; i < index2; i++)
        {
        table[i] = nums[i];
        }
        }
}
}


2.动态规划

public class Main
{
public static void main(String[] args)
  {
       Scanner sc = new Scanner(System.in);
       int  n = sc.nextInt();
       int[] weight = new int [n+1];
       int[] value = new int [n+1];
       for (int i = 1; i <= n; i++) weight[i] = sc.nextInt();
       for (int i = 1; i <= n; i++) value[i] = sc.nextInt();
       int total = sc.nextInt();
       sc.close();
       
       int dp[][] = new int[n+1][total+1];
       for (int i = 1; i < dp.length; i++)
       {
      for (int j = 1; j < dp[i].length; j++)
      {
      if (j >= weight[i])
            dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-weight[i]] + value[i]);
      else 
      dp[i][j] = dp[i-1][j];
      }
       }
       
       for (int i = 1; i < dp.length; i++)
       {
     for (int j = 1; j < dp[i].length; j++)
     {
    System.out.print(dp[i][j] + " ");  
     }
     System.out.println();
       }
       
}
}


### 关于 AcWing 平台上的 01 背包问题题解 #### 解决方案概述 在动态规划领域,01 背包问题是经典的子集选取问题之一。其核心目标是在给定容背包下,通过选择若干物品使得总价值最大化的同时不超过背包。以下是基于 AcWing 提供的相关资料以及标准算法设计方法的内容解析。 --- #### 动态规划状态转移方程推导 对于 01 背包问题,定义 `f[i][j]` 表示从前 `i` 个物品中选出一些放入容为 `j` 的背包所能获得的最大价值,则有如下两种情况: - **不选第 `i` 个物品**:此时最大价值等于前 `i-1` 个物品在容为 `j` 下的结果,即 `f[i][j] = f[i-1][j]`。 - **选第 `i` 个物品**:前提是当前背包剩余空间能够容纳该物品(即 `j >= v[i]`),则最大价值为 `f[i][j] = f[i-1][j - v[i]] + w[i]`。 综合上述两部分可得最终的状态转移方程: \[ f[i][j] = \max(f[i-1][j], f[i-1][j-v[i]] + w[i]) \] 其中 \(v[i]\) 和 \(w[i]\) 分别表示第 \(i\) 个物品的体积和价值[^2]。 --- #### 空间复杂度优化至 O(m) 为了减少二维数组的空间消耗,可以通过观察发现每次计算仅依赖上一层的数据 (`f[i-1][...]`),因此可以用一维数组代替二位数组来存储中间结果。具体实现方式是从右向左更新 `f[j]` 值以避免覆盖未使用的旧值。 代码片段展示了一种典型的一维 DP 实现形式: ```cpp #include <iostream> using namespace std; const int N = 1e3 + 10; int f[N]; int main(){ int n, m; // 物品背包 cin >> n >> m; int v[n+1], w[n+1]; 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--) f[j]=max(f[j],f[j-v[i]]+w[i]); cout<<f[m]<<endl; } ``` 此版本利用了滚动数组技术简化内存占用,并保持逻辑一致性[^5]。 --- #### 边界条件处理 当初始化阶段设置所有可能达到的位置初始值均为零时,意味着没有任何物品被放置之前任何大小的袋子都为空白状态;而对于那些不可能触达的情况(比如超过实际存在的货物总数),它们自然保留默认最小整数值(-INF 或者简单设成0 如果只关心正值收益的话)。 另外需要注意输入参数的有效范围验证,防止越界访问错误发生。 --- #### 时间复杂度分析 整个过程涉及双重嵌套循环结构——外层迭代每一个待考察对象\(O(n)\),内层扫描从高到底遍历可装载区间\([v_i,m]\), 整体时间开销大约为\(O(n*m)\). --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值