背包九讲——01背包(降维+常数级优化)

2024-03-06 18:58

本文主要是介绍背包九讲——01背包(降维+常数级优化),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目:

    共n个物体,第i个重量为w[i],价值v[i],背包最多能背不超过W的物体,求最大的价值

分析:

    每个物体只有一个,在容量允许时(W>w[i]),则对于每个物体只有取、不取两种选择

    状态:dp[i][j]:前i个物体,在容量为j的时候,最大的价值

    状态转移:

  

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

二维核心:

for(i = 1; i<=n; i++)
{for(j = 0; j<=W; j++){if(j<w[i])dp[i][j] = dp[i-1][j];elsedp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]] + v[i]);}
}
二维代码:

#include <stdio.h>
#include <iostream>
#include <string.h>
#include <string>
#include <math.h>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <vector>using namespace std;int w[100], v[100];
int dp[100][100];int main()
{freopen("a.txt", "r", stdin);int n, W, i, j;while(~scanf("%d%d", &W, &n)){memset(dp, 0, sizeof(dp));for(i = 1; i<=n; i++){scanf("%d%d", &w[i], &v[i]);}for(i = 1; i<=n; i++){for(j = 0; j<=W; j++){if(j<w[i])dp[i][j] = dp[i-1][j];elsedp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]] + v[i]);}}printf("%d\n", dp[n][W]);}return 0;
}

降维:

    减行,第i个物体的更新,只依赖于第i-1个的物体的结果

    所以可以用滚动数组,每次只存i和i-1时候的值 (可得:dp[n][W] → dp[2][W] )

    删行,第i个物体在容积为j状态的更新,只依赖i-1物体容量里j-w[i]的状态的结果

    所以,从后面开始向前更新,则求j位置时候,j-w[i]的值依旧为i-1时候的值(可得:dp[n][W] → dp[W] )

一维核心:

for(i = 1; i<=n; i++)
{for(j = W; j>=w[i]; j--) //从后向前,此时dp[j-w[i]]相当于dp[i-1][j-w[i]]{dp[j] = max(dp[j], dp[j-w[i]] + v[i]);}
}
一维代码:
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <string>
#include <math.h>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <vector>using namespace std;int w[100], v[100];
int dp[100];int main()
{freopen("a.txt", "r", stdin);int n, W, i, j;while(~scanf("%d%d", &W, &n)){memset(dp, 0, sizeof(dp));for(i = 1; i<=n; i++){scanf("%d%d", &w[i], &v[i]);}for(i = 1; i<=n; i++){for(j = W; j>=w[i]; j--){if(j>=v[i])   dp[j] = max(dp[j], dp[j-w[i]] + v[i]);}}printf("%d\n", dp[W]);}return 0;
}

初始化:

    1、memset(dp, 0, sizeof(dp))

        求不超过容积的W的最大价值

        容积有剩余的状态依旧有值,为前一个恰好装满最优解的值

    2、memset(dp, -0x3f, sizeof(dp)); //负无穷、不可达点(当前值约为:-1e+10)

        求恰好装满容积的最大价值(可能无解)

        当且仅当恰好装满的状态有值,其他存在空白容积的状态无法到达

常数级优化:

    一维中的内循环下限,由j>=w[i] → j>=max{w[i], W-(∑(i,n)w[i])}

    1、下限为j>=w[i]时候

        在所有剩余容积大于等于w[i]时候,选择取、不取第i物品

    2、下限为j>=max{w[i], W-(∑(i,n)w[i])}时候

        只更新在i+1时候需要用到的状态,并不把所以可能状态求出

常数级优化代码:

#include <stdio.h>
#include <iostream>
#include <string.h>
#include <string>
#include <math.h>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <vector>using namespace std;int w[100], v[100];
int dp[100];int main()
{freopen("a.txt", "r", stdin);int n, W, i, j;while(~scanf("%d%d", &W, &n)){memset(dp, 0, sizeof(dp));for(i = 1; i<=n; i++){scanf("%d%d", &w[i], &v[i]);}int lower, sum = 0;for(i = 1; i<=n; i++){if(i!=1) sum += w[i-1];lower = max(sum, w[i]);for(j = W; j>=lower; j--){dp[j] = max(dp[j], dp[j-w[i]] + v[i]);}}printf("%d\n", dp[W]);}return 0;
}
大神总结的,博客原址http://739789987.blog.51cto.com/8328242/1438296

                  

这篇关于背包九讲——01背包(降维+常数级优化)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/781008

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

HDFS—存储优化(纠删码)

纠删码原理 HDFS 默认情况下,一个文件有3个副本,这样提高了数据的可靠性,但也带来了2倍的冗余开销。 Hadoop3.x 引入了纠删码,采用计算的方式,可以节省约50%左右的存储空间。 此种方式节约了空间,但是会增加 cpu 的计算。 纠删码策略是给具体一个路径设置。所有往此路径下存储的文件,都会执行此策略。 默认只开启对 RS-6-3-1024k

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

poj2576(二维背包)

题意:n个人分成两组,两组人数只差小于1 , 并且体重只差最小 对于人数要求恰好装满,对于体重要求尽量多,一开始没做出来,看了下解题,按照自己的感觉写,然后a了 状态转移方程:dp[i][j] = max(dp[i][j],dp[i-1][j-c[k]]+c[k]);其中i表示人数,j表示背包容量,k表示输入的体重的 代码如下: #include<iostream>#include<

hdu2159(二维背包)

这是我的第一道二维背包题,没想到自己一下子就A了,但是代码写的比较乱,下面的代码是我有重新修改的 状态转移:dp[i][j] = max(dp[i][j], dp[i-1][j-c[z]]+v[z]); 其中dp[i][j]表示,打了i个怪物,消耗j的耐力值,所得到的最大经验值 代码如下: #include<iostream>#include<algorithm>#include<

csu(背包的变形题)

题目链接 这是一道背包的变形题目。好题呀 题意:给n个怪物,m个人,每个人的魔法消耗和魔法伤害不同,求打死所有怪物所需的魔法 #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<queue>#include<set>//#include<u>#include<map

hdu1011(背包树形DP)

没有完全理解这题, m个人,攻打一个map,map的入口是1,在攻打某个结点之前要先攻打其他一个结点 dp[i][j]表示m个人攻打以第i个结点为根节点的子树得到的最优解 状态转移dp[i][ j ] = max(dp[i][j], dp[i][k]+dp[t][j-k]),其中t是i结点的子节点 代码如下: #include<iostream>#include<algorithm

hdu1171(母函数或多重背包)

题意:把物品分成两份,使得价值最接近 可以用背包,或者是母函数来解,母函数(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v) 其中指数为价值,每一项的数目为(该物品数+1)个 代码如下: #include<iostream>#include<algorithm>

hdu 2602 and poj 3624(01背包)

01背包的模板题。 hdu2602代码: #include<stdio.h>#include<string.h>const int MaxN = 1001;int max(int a, int b){return a > b ? a : b;}int w[MaxN];int v[MaxN];int dp[MaxN];int main(){int T;int N, V;s

MySQL高性能优化规范

前言:      笔者最近上班途中突然想丰富下自己的数据库优化技能。于是在查阅了多篇文章后,总结出了这篇! 数据库命令规范 所有数据库对象名称必须使用小写字母并用下划线分割 所有数据库对象名称禁止使用mysql保留关键字(如果表名中包含关键字查询时,需要将其用单引号括起来) 数据库对象的命名要能做到见名识意,并且最后不要超过32个字符 临时库表必须以tmp_为前缀并以日期为后缀,备份