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

0-1 背包问题(模板)

前言:dp问题的题目就是多做题,多总结,之后遇到不同的题的时候与原先做过类似的题比较,然后猜一个状态表示,看一看能不能推出状态转移方程,能推出来就说明状态表示对了,不行就再做出调整。是在不会咋看答案,吸收这里面的经验。

例题1: 01背包_牛客题霸_牛客网          

1.题目解析

简而言之就是在n个物品中选出体积总和不大于v的最大重量。

2.算法原理(动态规划 - 线性dp)

1.状态表示

对于这个线性dp问题我们都是以最后一个位置xxxx,然后根据最后一个位置分类讨论。

此题为:设:dp[i][j] 表示在前 i 个物品中挑选出体积不超过j的最大体积。

那么对于i位置的物品,有选和不选两种情况,但选是有条件的,就是i位置的体积必须不大于j。

2.状态转移方程

那么:选 , 需满足条件   arr[i] <= j      =>    dp[i][j]  =  Math.max(dp[i-1][j-v[i]] + w[i],dp[i-1][j]);

          不选     dp[i][j]   =   dp[i-1][j];

3.初始化

我们多加一行,一列,方便写代码(不用做越界判断,这个很常用,就不过多解释)

对于 i = 0 时,说明0个物品,无论体积多大,初始化都为0;

对于 v = 0 时,说明体积为0,无论物品多少,都不能加入新的物品,初始化都为0;

所以不用初始化。

4.填表(dp这个数组)顺序

从左->右,上-> 下    因为状态表达式当前位置依赖的是左边的位置或左上方的位置。

5.返回值

我们是要求前n个物品中体积不超过v的最大的重量,根据状态表示,可以很容易的得出为dp[n][v]

3.代码

import java.util.*;public class Solution {public int knapsack (int V, int n, int[][] vw) {int[][] dp = new int[n+1][V+1];for(int i = 1;i <= n;i++){for(int j = 1;j <= V;j++){if(j >= vw[i-1][0]){dp[i][j] = Math.max(dp[i-1][j-vw[i-1][0]] + vw[i-1][1],dp[i-1][j]);}else{dp[i][j] = dp[i-1][j];}}}return dp[n][V];}
}

例题2:小红取数_牛客题霸_牛客网(变式)

上面的题如果会了,可以挑战一下这个,两题有很大的相似。

补充知识:

   同余定理:  如果 A % k = a , B % k = b 且( A + B ) % k == 0 那么   (a + b) % k = 0。    

1.题目解析

在n个数中挑选出 和 是 k的倍数的最大值。

2.算法原理(动态规划)

1.状态表示:(对于这个状态表示我就试了很多种)

设:dp[ i ][ j ] 表示在前 i 个数中选出是k倍数的最大和。 

2.状态转移方程

那么对于 i 位置的数,就有选和不选两种情况。

选: 需要 ( dp[ i - 1 ][ tep ] + arr[ i ] ) % k =  j ,  tep = (j - arr[i] % k + k ) % k  

dp[ i ][ j ] = Math.max(dp[i-1][tep] + arr[i] , dp[ i - 1 ][ j ]) ,因为要最大所以在两种情况取最大值。

不选: dp[ i ][ j ] = dp[ i - 1 ][ j ] 。

3.初始化

我们这里初始化dp为: long[][] dp = new long[n+1][k];   

那么 对于  前 0 的 数,也就没有数嘛,dp[ 0 ][ xx ] = 0;

这样便不用初始化了

4.填表顺序

根据状态方程,当前位置的值 依赖上一行的数,所以我们从左 -> 右  ,上 -> 下;

5.返回值

有状态表示得:dp[n][0]   

3.代码

import java.util.*;public class Main{public static void main(String[] args){//处理输入和初始化Scanner sc = new Scanner(System.in);int n = sc.nextInt();int k = sc.nextInt();long[] arr = new long[n];for(int i = 0;i < n;i++){arr[i] = sc.nextLong();}long[][] dp = new long[n+1][k];// 主逻辑for(int i = 1;i <= n;i++){for(int j = 0;j < k;j++){int tep = (int)((j - arr[i-1] % k + k) % k);if((dp[i-1][tep] + arr[i-1]) % k == j){dp[i][j] = Math.max(dp[i-1][j],dp[i-1][tep] + arr[i-1]);}else{dp[i][j] = dp[i-1][j];}}}System.out.println(dp[n][0] == 0 ? -1 : dp[n][0]);}
}

ok, 结束了。                                                                                          时间匆匆,马上就开学了。

http://www.dtcms.com/a/341108.html

相关文章:

  • 汽车ECU实现数据安全存储(机密性保护)的一种方案
  • Ubuntu apt安装nginx
  • 使用Spring Retry组件优雅地实现重试
  • Java 定时任务 - 从基础到高阶使用 - 从 Timer 到 Quart
  • 数据结构 二叉树 二叉树链式结构的实现
  • 数据分析师常用命令
  • 数据结构中的列表:深度解析数组与链表的实现与抉择
  • PyTorch API 3 - distributed
  • 前后端联合实现文件上传,实现 SQL Server image 类型文件上传
  • 51单片机-驱动LED点阵模块教程
  • SQL-leetcode—3374. 首字母大写 II
  • Docker--安装MySQL、Redis
  • 面试常考的 SQL 窗口函数汇总
  • 【Tech Arch】Apache Pig大数据处理的高效利器
  • 深入理解数据结构:从数组、链表到B树家族
  • 数据结构:利用旋转在AVL树中维持平衡(Inserting in AVL with Rotation)
  • FastAPI初学
  • PyTorch API 1
  • 新能源知识库(81)新能源半实物仿真平台介绍
  • C/C++ Linux系统编程:详解常见的系统调用函数,文件I/O核心:open, close, read, write
  • 【C++】基础:C++11-14-17常用新特性介绍
  • 计算机网络技术-局域网配置(Day.4)
  • 微信小程序授权登录+JWT
  • shell间接引用
  • CVE-2018-12613 漏洞复现
  • 为什么我的UI界面会突然卡顿,失去响应
  • FLASK项目快速构建
  • 用TestComplete打造高效CI/CD测试流程
  • nodejs mongodb基础
  • 【论文阅读】-《SIGN-OPT: A QUERY-EFFICIENT HARD-LABEL ADVERSARIAL ATTACK》