背包问题大合集

news/2024/10/6 3:37:28/文章来源:https://www.cnblogs.com/hanlinyuan/p/18288236

dp背包3步曲

1.确定dp[i] [v]的含义(一维的话是dp[v]) :在 0…i 的物品中,体积为 v 的背包中,能够拿到的最大价值为 dp[i] [v]。
2.求关系式不拿物品:(物品数量减少)一维:dp[v] 二维:dp[i] [v] = dp[i-1] [v]拿:(物品数量减少,背包体积减物品体积)一维:dp[v-weight[i]] 二维:dp[i] [v] = dp[i-1] [v-weight[i]]一维背包:
//遍历物品的数量Nfor (int i = 1; i <= n; i++) {//遍历背包的容量V,但是从大到小进行遍历,如果背包容量大于物品体积就拿for (int j = capacity; j >= weights[i]; j--) {//不拿(背包体积不变)和拿(背包体积减少再加上物品价值),进行比大小,取大值。dp[j] = Math.max(dp[j], dp[j - weights[i]] + values[i]);}}

二维背包:

//遍历物品的数量Nfor(int i = 1;i<= n ; i++){//遍历背包的容量Vfor(int j = 0; j <= c ; j++ ){//如果背包体积小于物品的体积,放不下就不拿了if(j<v[i]){dp[i][j] = dp[i-1][j];}else{//不拿(物品数量-1)和拿(物品数量-1,并且背包体积减少再加上物品价值),进行比大小,取大值。dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);}}}

二维背包

import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int numCases = sc.nextInt();  // Number of test casesfor (int caseNum = 0; caseNum < numCases; caseNum++) {int numItems = sc.nextInt();  // Number of itemsint capacity = sc.nextInt();  // Maximum capacity of the knapsackint limit = sc.nextInt();     // Maximum weight limitint[] values = new int[numItems + 1];int[] weights = new int[numItems + 1];int[] profits = new int[numItems + 1];for (int i = 1; i <= numItems; i++) {values[i] = sc.nextInt();  // Value of the itemweights[i] = sc.nextInt(); // Weight of the itemprofits[i] = sc.nextInt(); // Profit of the item}int[][] dp = new int[capacity + 1][limit + 1];  // DP tablefor (int i = 1; i <= numItems; i++) {for (int j = capacity; j >= values[i]; j--) {for (int k = limit; k >= weights[i]; k--) {dp[j][k] = Math.max(dp[j][k], dp[j - values[i]][k - weights[i]] + profits[i]);}}}System.out.println(dp[capacity][limit]);}sc.close();}
}

如果每个物品只能用一次,反向更新是必要的;如果每个物品可以用多次,则可以正向更新。

01背包

import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int numCases = sc.nextInt();  // Number of test casesfor (int caseNum = 0; caseNum < numCases; caseNum++) {int numItems = sc.nextInt();  // Number of itemsint capacity = sc.nextInt();  // Maximum capacity of the knapsackint limit = sc.nextInt();     // Maximum weight limitint[] values = new int[numItems + 1];int[] weights = new int[numItems + 1];int[] profits = new int[numItems + 1];for (int i = 1; i <= numItems; i++) {values[i] = sc.nextInt();  // Value of the itemweights[i] = sc.nextInt(); // Weight of the itemprofits[i] = sc.nextInt(); // Profit of the item}int[][] dp = new int[capacity + 1][limit + 1];  // DP tablefor (int i = 1; i <= numItems; i++) {for (int j = capacity; j >= values[i]; j--) {for (int k = limit; k >= weights[i]; k--) {dp[j][k] = Math.max(dp[j][k], dp[j - values[i]][k - weights[i]] + profits[i]);}}}System.out.println(dp[capacity][limit]);}sc.close();}
}

多重背包

public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int nt = sc.nextInt();for (int t = 0; t < nt; t++) {int n = sc.nextInt(); // 物品种类int c = sc.nextInt(); // 背包容量int[] w = new int[n + 1];int[] v = new int[n + 1];int[] m = new int[n + 1];for (int i = 1; i <= n; i++) { // 索引从1开始w[i] = sc.nextInt(); // 物品重量v[i] = sc.nextInt(); // 物品价值m[i] = sc.nextInt(); // 物品个数}int[] dp = new int[c + 1];for (int i = 1; i <= n; i++) {      // 遍历物品if (m[i] * w[i] >= c) {         // 如果物品数量无限多(足够多),相当于完全背包for (int j = w[i]; j <= c; j++) {dp[j] = Math.max(dp[j], dp[j - w[i]] + v[i]);}} else {                                // 如果物品数量有限,先用二进制优化,再当多重背包做,减少循环次数int num = m[i];                       //num表示物品的剩余数量for (int k = 1; num > 0; k <<= 1) {     //k表示当前二进制位的值,当前物品数量>0就说明可以进行二进制优化//取小的,确保每次取的物品数量不超过实际剩余数量,在k变大时,可能会超过num,这时就需要取实际剩余的num而不是k。int cnt = Math.min(k, num);         //cnt表示取出的物品数量num -= cnt;                        //减去已从背包分出去的物品for (int j = c; j >= cnt * w[i]; j--) {dp[j] = Math.max(dp[j], dp[j - cnt * w[i]] + cnt * v[i]);}}}}System.out.println(dp[c]); // 输出结果}sc.close();}
}

最长公共子序列:

import java.util.Scanner;public class Main {static char[] x;static char[] y;static int[][] dp; // 字符串 X 和字符串 Y 的最长公共子序列的长度。public static void main(String[] args) {Scanner sc = new Scanner(System.in);int t = sc.nextInt();sc.nextLine(); // 吸收换行符for (int i = 1; i <= t; i++) {x = sc.nextLine().toCharArray();y = sc.nextLine().toCharArray();// 初始化dp数组,也就是x,y数组的长度int xl = x.length;int yl = y.length;dp = new int[xl + 1][yl + 1]; // 初始化dp数组大小// 循环数组从1开始,不用加dp[][],因为已经初始化了for (int j = 1; j <= xl; j++) { for (int k = 1; k <= yl; k++) {// 如果上一个字符相同,就计算出当前值,更新当前的公共子序列长度if (x[j - 1] == y[k - 1]) {dp[j][k] = dp[j - 1][k - 1] + 1;} else {// 如果不相同,在之前算出来的答案找最适合的,取公共子序列的(二维方向的)前一位进行对比,取大的作为最长公共子序列。dp[j][k] = Math.max(dp[j][k - 1], dp[j - 1][k]);}}}System.out.println(dp[xl][yl]);}sc.close(); // 关闭读写流}}

最长上升子序列:

核心思路:通过动态规划的方法,用 dp[i] 表示以 nums[i] 结尾的最长上升子序列的长度,遍历数组,更新每个位置的 dp[i] 值,同时记录整个数组的最长上升子序列长度 maxans

import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int size = scanner.nextInt();int[] numbers = new int[size];// 读取输入数组for (int i = 0; i < size; i++) {numbers[i] = scanner.nextInt();}int result = lengthOfLIS(numbers);System.out.println(result);
}public static int lengthOfLIS(int[] nums) {// dp[i] 表示下标i在 nums[i] 时,也就是0-i的最长上升子序列的长度int[] dp = new int[nums.length];dp[0] = 1; // 初始化,每个元素自身构成一个长度为 1 的子序列int maxans = 1; // 记录最长上升子序列的长度//外层循环从1开始遍历每个元素,计算以该元素结尾的最长上升子序列的长度。for (int i = 1; i < nums.length; i++) {dp[i] = 1; // 也就是初始化dp的每一个元素为1,可以写到外面for (int j = 0; j < i; j++) {// 如果 nums[i] 大于 nums[j],则可以将 nums[i] 加入到以 nums[j] 结尾的子序列中if (nums[i] > nums[j]) {//既然要更新当前下标i位置的最长上升子序列的长度dp,那就是拿上一个已经算出来的值+1更新,当然了要进行对比取最大值,如果当前的dp[i]比dp[j]还大,那就还是使用当前的。dp[i] = Math.max(dp[i], dp[j] + 1);		}}// 更新最长上升子序列的长度maxans = Math.max(maxans, dp[i]);}return maxans;
}

超市搞活动(01背包)

#include <iostream>
#include <vector>
#include <algorithm>using namespace std;int getMax(int a, int b) {if (a > b) {return a;} else {return b;}
}int knapsack(int capacity, int numItems, int profits[], int weights[]) {vector<int> dp(capacity + 1, 0);for (int i = 0; i < numItems; i++) {for (int j = weights[i]; j <= capacity; j++) {dp[j] = getMax(dp[j], dp[j - weights[i]] + profits[i]);}}return dp[capacity];
}int main() {int capacity, numItems;while (cin >> capacity >> numItems) {int profits[numItems], weights[numItems];for (int i = 0; i < numItems; i++) {cin >> profits[i] >> weights[i];}int result = knapsack(capacity, numItems, profits, weights);cout << result << endl;}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/739673.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WebRTC入门

效果展示基础概念WebRTC指的是基于web的实时视频通话,其实就相当于A->B发直播画面,同时B->A发送直播画面,这样就是视频聊天了 WebRTC的视频通话是A和B两两之间进行的 WebRTC通话双方通过一个公共的中心服务器找到对方,就像聊天室一样 WebRTC的连接过程一般是A通过web…

组装8 地图移动

8,地图移动, 建立一个SURFACE,大小是18* unitx 19* unity 地图坐标 X,Y 坐标在显示中间 读取这个坐标 18 * 19 范围的地图数据,贴图到SURFACE 上。 问题 1,OBJECT第三层的贴图是UNITX,HEIGHT的大小, 这个HEIGHT的高度需要读取超过19个UNITY 的OBJECT,应该+12就可…

KubeSphere 社区双周报|2024.06.21-07.04

KubeSphere 社区双周报主要整理展示新增的贡献者名单和证书、新增的讲师证书以及两周内提交过 commit 的贡献者,并对近期重要的 PR 进行解析,同时还包含了线上/线下活动和布道推广等一系列社区动态。 本次双周报涵盖时间为:2024.06.21-07.04。 贡献者名单新晋 KubeSphere co…

HSQL 数据库介绍(1)--简介

HSQLDB(HyperSQL Database)是一款用 Java 编写的关系数据库管理系统;它提供了许多功能,并严格遵循最新的 SQL 和 JDBC 4.2 标准;本文主要介绍其基本概念及安装。 1、简介 HyperSQL Database(HSQLDB)是一款现代的关系数据库系统。HSQLDB 遵循国际 ISO SQL:2016 标准,支持…

lazarus 设置中文界面及开启代码提示

1.选择, Tools-Options-Environment-General-Language 选择Chinese[zh-CN],点击ok,重启即可 2.开启标识符补全,代码提示,如下图设置即可 本人小站:www.shibanyan.com

《Programming from the Ground Up》阅读笔记:p19-p48

《Programming from the Ground Up》学习第2天,p19-p48总结,总计30页。 一、技术总结 1.object file p20, An object file is code that is in the machines language, but has not been completely put together。 之前在很多地方都看到object file这个概念,但都没有看到起…

Qt/C++音视频开发78-获取本地摄像头支持的分辨率/帧率/格式等信息/mjpeg/yuyv/h264

一、前言 上一篇文章讲到用ffmpeg命令方式执行打印到日志输出,可以拿到本地摄像头设备信息,顺藤摸瓜,发现可以通过执行 ffmpeg -f dshow -list_options true -i video="Webcam" 命令获取指定摄像头设备的分辨率帧率格式等信息,会有很多条。那为什么需要这个功能呢…

Lazarus的安装

推荐安装秋风绿色版lazarus,秋风的blog上有绿色版百度网盘的下载地址,对于没有VIP会员的可以去QQ群下载,群号:103341107,速度比网盘好些 下载完成后,推荐解压到非系统盘根目录,在根目录里找到“lazarus绿化工具-x86_64-win64.exe”并运行。上图的路径是你的程序所在目录…

关于电源的基础知识

基础知识很多时候,都没有直接的作用。但是不积跬步无以至千里,不积小流无以成江海。接下来就用一页笔记,简单说明一下不理想源的输出阻抗。在一个电路系统中,前级和后级的连接,大多需要计算输入输出阻抗的。

Denso Create Programming Contest 2024(AtCoder Beginner Contest 361)

Denso Create Programming Contest 2024(AtCoder Beginner Contest 361)\(A\) Insert \(AC\)循环结构。点击查看代码 int a[200]; int main() {int n,k,x,i;cin>>n>>k>>x;for(i=1;i<=n;i++){cin>>a[i];cout<<a[i]<<" ";i…

浅谈进程隐藏技术

在之前几篇文章已经学习了解了几种钩取的方法,这篇文章就利用钩取方式完成进程隐藏的效果。在实现进程隐藏时,首先需要明确遍历进程的方法。前言 在之前几篇文章已经学习了解了几种钩取的方法 ● 浅谈调试模式钩取 ● 浅谈热补丁 ● 浅谈内联钩取原理与实现 ● 导入地址表钩取…