当前位置: 首页 > news >正文

CSP-J/S 复赛算法 背包DP

文章目录

  • 前言
  • 背包DP的简介
    • 问题描述
    • 目标
    • 解决方法
    • 1. **定义状态**
    • 2. **状态转移方程**
    • 3. **初始化**
    • 4. **目标**
    • 举个例子
    • 动态规划解决背包问题的核心
  • DP背包问题示例代码
      • 问题描述
      • 代码实现
      • 核心代码讲解:
      • 举例:
      • 总结:
  • 总结


前言

背包问题是算法竞赛中的经典题型之一,特别是在CSP-J/S(中国信息学奥林匹克竞赛)复赛中,动态规划(DP)解决背包问题是一个常见且基础的重要内容。背包DP问题通过构建状态转移方程,利用「无后效性」这一特性,可以高效地解决一系列组合优化问题。本文将简要介绍如何在背包问题中运用动态规划思想,通过对状态的设计与转移公式的推导,最终求解出最优解。这种方法不仅是算法竞赛中的常见考点,也是在实际应用中有广泛运用的技巧。


背包DP的简介

背包问题(Knapsack Problem)是动态规划(DP)中的经典问题之一,它描述了一个选择物品的最优化问题。背包问题有很多变种,其中最常见的是0-1背包问题。我们以这个为例介绍一下。

问题描述

假设你有一个容量为 (C) 的背包,以及 (n) 件物品。每件物品都有两个属性:

  1. 重量 (w_i):物品的重量。
  2. 价值 (v_i):物品的价值。

你需要从这 (n) 件物品中选择若干件装入背包,但不能超过背包的容量 (C)。同时,你希望背包中的物品总价值最大化。每件物品只能被选一次(即「0-1」背包的「0-1」指的是每个物品只能取或者不取,不能分割)。

目标

最大化装入背包的物品的总价值,条件是物品的总重量不超过背包容量。

解决方法

动态规划(DP)可以很好地解决这个问题。我们一步步设计DP的步骤:

1. 定义状态

用 (dp[i][j]) 表示前 (i) 件物品在容量为 (j) 的背包里能够获得的最大价值。

  • 例如,(dp[3][5]) 表示用前三件物品在容量为5的背包里能获得的最大价值。

2. 状态转移方程

对第 (i) 件物品,我们有两种选择:

  • 不选择这件物品:那么最大价值就是前 (i-1) 件物品在容量 (j) 下的最大价值,表达式为:
    d p [ i ] [ j ] = d p [ i − 1 ] [ j ] dp[i][j] = dp[i-1][j] dp[i][j]=dp[i1][j]
  • 选择这件物品:如果当前物品 (i) 的重量 (w_i \leq j),那么我们可以选择它,最大价值就是当前物品价值 (v_i) 加上剩下的背包容量 (j - w_i) 时前 (i-1) 件物品的最大价值,表达式为:
    d p [ i ] [ j ] = d p [ i − 1 ] [ j − w i ] + v i dp[i][j] = dp[i-1][j-w_i] + v_i dp[i][j]=dp[i1][jwi]+vi

因此,综合这两种情况,状态转移方程为:
d p [ i ] [ j ] = max ⁡ ( d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − w i ] + v i ) dp[i][j] = \max(dp[i-1][j], dp[i-1][j-w_i] + v_i) dp[i][j]=max(dp[i1][j],dp[i1][jwi]+vi)

3. 初始化

对于初始状态,若不选任何物品或背包容量为 0,那么最大价值都是 0,因此:
d p [ 0 ] [ j ] = 0 (对于所有的  j ) dp[0][j] = 0 \quad \text{(对于所有的 \(j\))} dp[0][j]=0(对于所有的 j)
d p [ i ] [ 0 ] = 0 (对于所有的  i ) dp[i][0] = 0 \quad \text{(对于所有的 \(i\))} dp[i][0]=0(对于所有的 i)

4. 目标

最终,我们要的解就是 (dp[n][C]),即前 (n) 件物品在背包容量为 (C) 的情况下可以获得的最大价值。

举个例子

假设有 4 件物品,它们的重量和价值如下:

  • 物品 1:重量 2,价值 3
  • 物品 2:重量 3,价值 4
  • 物品 3:重量 4,价值 5
  • 物品 4:重量 5,价值 8

背包容量为 8。求解能够装入背包的最大价值是多少?

通过 DP 表的推算,最终可以得出最大价值为 11(选择物品 2 和物品 4,总重量为 3 + 5 = 8,总价值为 4 + 8 = 11)。

动态规划解决背包问题的核心

  • 无后效性:当前的状态(选择第几件物品,剩余容量多少)只与之前的状态相关,而不受未来的决策影响。
  • 子问题重叠:每一个子问题的解会被多次使用,因此通过 DP 的方式,可以避免重复计算,提高效率。

这种方法非常适合解决背包问题及其他类似的最优化问题。

DP背包问题示例代码

以下是一个用动态规划(DP)解决 0-1背包问题 的 C 语言代码示例,并附上核心代码的讲解。

问题描述

我们有 n 个物品,每个物品有重量 w[i] 和价值 v[i]。背包的容量为 C,我们需要选择物品,使得在不超过背包容量的情况下,物品的总价值最大化。

代码实现

#include <stdio.h>#define MAX_N 100  // 物品最大数量
#define MAX_W 1000 // 背包最大容量int dp[MAX_N + 1][MAX_W + 1]; // DP表,保存最大价值int max(int a, int b) {return (a > b) ? a : b;
}int knapsack(int n, int W, int w[], int v[]) {// 初始化DP表,0件物品或容量为0时价值都为0for (int i = 0; i <= n; i++) {for (int j = 0; j <= W; j++) {dp[i][j] = 0;}}// 动态规划,计算最大价值for (int i = 1; i <= n; i++) {for (int j = 0; j <= W; j++) {if (w[i-1] <= j) {// 状态转移方程:dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i-1]] + v[i-1])dp[i][j] = max(dp[i-1][j], dp[i-1][j - w[i-1]] + v[i-1]);} else {// 如果当前物品重量大于容量,不能选该物品dp[i][j] = dp[i-1][j];}}}// 返回最大价值return dp[n][W];
}int main() {int n = 4; // 物品数量int W = 8; // 背包容量int w[] = {2, 3, 4, 5}; // 每个物品的重量int v[] = {3, 4, 5, 8}; // 每个物品的价值// 调用背包算法int max_value = knapsack(n, W, w, v);printf("最大价值: %d\n", max_value);return 0;
}

核心代码讲解:

  1. dp数组的定义:

    int dp[MAX_N + 1][MAX_W + 1];
    

    这里的 dp[i][j] 表示前 i 件物品在背包容量为 j 的时候可以获得的最大价值。dp 的维度是 (n+1) x (W+1),其中 n 是物品数量,W 是背包容量。

  2. 初始化DP表:

    for (int i = 0; i <= n; i++) {for (int j = 0; j <= W; j++) {dp[i][j] = 0;}
    }
    

    初始状态是没有物品(即 i = 0)或者背包容量为 0 时(即 j = 0),那么背包中的最大价值显然是 0。这个初始化确保了后续状态转移时有合理的初始值。

  3. 状态转移方程:

    dp[i][j] = max(dp[i-1][j], dp[i-1][j - w[i-1]] + v[i-1]);
    

    这是动态规划的核心部分,对于每个物品,我们有两种选择:

    • 不选第 i 件物品:此时最大价值和之前一样,即 dp[i-1][j]
    • 选第 i 件物品:此时需要确保物品重量小于等于背包容量(即 w[i-1] <= j),那么最大价值就是当前物品的价值 v[i-1] 加上背包剩余容量 j - w[i-1] 的最大价值 dp[i-1][j - w[i-1]]
  4. 返回结果:

    return dp[n][W];
    

    最终我们需要的答案是 dp[n][W],即前 n 件物品在背包容量为 W 时能够获得的最大价值。

举例:

对于输入:

  • 物品数量:4
  • 背包容量:8
  • 物品重量:{2, 3, 4, 5}
  • 物品价值:{3, 4, 5, 8}

程序输出:

最大价值: 11

这个结果对应于选择了物品 2 和物品 4,总重量为 3 + 5 = 8,总价值为 4 + 8 = 11。

总结:

这个代码通过动态规划解决 0-1 背包问题的核心在于状态转移方程,它通过子问题的解来推导出全局问题的最优解。每个子问题的解被存储在 dp 数组中,从而避免重复计算,极大地提高了效率。


总结

背包DP算法通过构建一个DP表格,依次推算每个子问题的最优解,最终得出整个问题的最优解。核心在于合理设计状态和状态转移方程,使得每一步的选择都依赖于之前的子问题结果。在CSP-J/S复赛中,背包问题的灵活变化考验选手对动态规划思想的掌握,理解其原理后能够有效提升问题解决的效率。熟练掌握背包问题的动态规划方法,不仅能够应对竞赛中的挑战,更能为更复杂的优化问题打下坚实基础。

http://www.lryc.cn/news/453953.html

相关文章:

  • 如何评估和部署 IT 运维系统?
  • 正态分布的极大似然估计一个示例,详细展开的方程求解步骤
  • s7-200SMART编程软件下载
  • Linux驱动开发常用调试方法汇总
  • 将列表中的各字符串sn连接成为一个字符串s使用;将各sn间隔开os.pathsep.join()
  • 算法题总结(八)——字符串
  • 大数据开发--1.2 Linux介绍及虚拟机网络配置
  • 2024CSP-J复赛易错点
  • pytorch 与 pytorch lightning, pytorch geometric 各个版本之间的关系
  • Spring Boot项目的创建与使用
  • pytorch常用函数view、sum、sequeeze、cat和chunk
  • 【STM32开发之寄存器版】(四)-独立看门狗IWDG
  • 【S32K3 RTD MCAL 篇1】 K344 KEY 控制 EMIOS PWM
  • 华为OD机试真题---绘图机器(计算面积)
  • HarmonyOs 查看官方文档使用弹窗
  • uniapp+Android智慧居家养老服务平台 0fjae微信小程序
  • 在一台电脑上实现网页与exe程序使用udp通信
  • 基于Java的GeoTools对Shapefile文件属性信息深度解析
  • 付费计量系统实体和接口(1)
  • 网易博客旧文----bacnet学习系列之四----VTS的初步使用
  • SpringIoC容器的初识
  • 队列的实现与讲解
  • hbuilderx+uniapp+Android健身房管理系统 微信小程序z488g
  • 自动驾驶-参考线生成
  • 厂商资源分享网站
  • 【ONE·Web || HTML】
  • MongoDB的安装与增删改查基本操作
  • Python水循环标准化对比算法实现
  • 【TypeScript】知识点梳理(一)
  • DMA方式在执行中断处理程序时不中断现行程序吗