01背包思想和优化

dp入门问题:01背包装下了我们的忧伤QWQ

  作为一枚乐于作死...呸,乐于学习的蒟蒻,当然要学会装包的

那么简单的描述一下01背包问题:

  小明有个bag,容量是m.小明面前有n个物品,每个物品有它的价值vi和它的体积wi,小明想知道用这个背包能装到的物品总价值最大是多少.

好,这就是一个最朴素的01背包问题,那么怎么解决呢.

稍加思索...dp嘛,从小问题解决到大问题.我们用一个数组dp[i][j]表示选第i件物品时容量为j可以得到的最大价值。

状态转移方程就出来啦:dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+[v[i]]);

其实01背包过程就是选与不选第i件物品,dp[i-1][j]实则就是不选第i件物品,dp[i-1][j-w[i]]+v[i]就是选了第i件物品,既然我们选了,那就要减掉它的wi再加上它的价值vi。然后在两者之间选最优方案就完美解决了

总的来说:01背包就是靠着第i-1的状态更新第i的状态

上代码:

再次开启脑洞:我们发现更新第i件物品的时候只需要用到第i-1的状态,之前的状态都可以抛弃,这样我们就可以抛弃i这个维度,只用一个维度保存j,这样做的的话,代码就变成了这样

注意这必须是逆序遍历,至于为什么呢?上面已经说过,01背包就是靠着第i-1的状态更新第i的状态,如果顺序遍历的话,第i状态的数据会覆盖掉第i-1状态的某一些数据,而这些被覆盖的数据保不准还有用于更新接下来的第i状态的,我们是要i-1更新i状态的,如果原i-1已经被覆盖成第i状态了,那么接下来就是用i状态更新i状态,显然是不符合定义的,而逆序遍历可以保证后面的数据先被更新成第i状态,前面的数据还是第i-1状态,那么用前面的数据(i-1状态)就可以保证不会出错

ps:这里可能有点绕,或许会不好理解,本来博主想用张动图解释解释的,奈何博主不会做动图QWQ,哪讲错了欢迎大家拍砖

原文地址:https://www.cnblogs.com/kekekuli/p/11739109.html

时间: 2024-10-09 09:29:57

01背包思想和优化的相关文章

NYOJ 654喜欢玩warcraft的ltl(01背包/常数级优化)

传送门 Description ltl 非常喜欢玩warcraft,因为warcraft十分讲究团队整体实力,而他自己现在也为升级而不拖累团队而努力. 他现在有很多个地点来选择去刷怪升级,但是在每一个地点他都要买上充足的补给和合适的道具,以免在刷怪的时候被怪物反杀了,每一个地点的怪物打完了就没有了(还居然不掉金钱跟装备),而且他只要选定了地点就一定会刷完该地点全部的怪物,同时获得对应的经验值.现在ltl 能给出每一个地点用来买补给和道具的钱和打完全部怪物所能获得的经验,但是他所拥有的钱是一定的.

01背包思想解决组合问题并输出组合

//01背包思想 每个数都有 选 与 不选 两种可能 #include<cstdio>int n, r;bool Vis[21] = {false}; void DFS(int index, int nowR){        //边界    if(index == n+1){            // 说明已经遍历完了 n个数        if(nowR == r) {          //说明刚好选了r个数             for(int i = 1; i <= n;

01 背包基础 - 空间优化 (滚动数组,一维阵列)

2017-09-03 11:39:16 writer:pprp 以很简单的一个动态规划问题为引入: 从左上角到右下角走过的路径和最大,问你最大为多少? 1.可以想到普通的dp 状态转移为: dp[i][j] = max(dp[i-1][j],dp[i][j-1]) + arr[i][j]; 2.采用滚动数组的方式-节约了不必要的空间 状态转移为:dp2[i%2][j] = max(dp2[(i+1)%2][j],dp2[i%2][j-1]) + arr[i][j]; 3.采用一维阵列的方式更加节

POJ1745Divisibility(01背包思想)

Divisibility Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 11151   Accepted: 3993 Description Consider an arbitrary sequence of integers. One can place + or - operators between integers in the sequence, thus deriving different arithmet

ZOJ1366经典dp(多重背包转01背包+优化空间)

1 //zoj1366类似背包的问题 2 //争取一遍AC 3 #include<iostream> 4 #include<string.h> 5 #include<stdio.h> 6 #define maxn 13 7 using namespace std; 8 9 int k[maxn]; 10 int n1[maxn]; 11 int c1[maxn]; 12 int c2[105]; 13 int dp[110000]; 14 int Cash,N1,N2;

SPOJ RENT 01背包的活用+二分

这个题目给定N航班的发出时间和结束时间以及价值,要求不冲突时间的最大价值 第一时间想到经典的N方DP,即对航班按发出时间排一下序之后每个i对前面的都扫一遍 时间过不了N有10万,只能想优化了,一开始想了个用树状数组记录每次加入某个航班之后 后面的所有在结束时间后的区间全部可以加一个最大值,但是首先时间区间的量更大,而且树状数组不好这么操作 后来实在没见过这种DP,还是看的别人的算法,还是挺叼的,不过其实还是沿用的背包思想 对于每个航班区间,我只需要考虑取或者不取,这样的话,对航班按出发时间S排序

杭电1203--I NEED A OFFER!(01背包)

I NEED A OFFER! Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 20582    Accepted Submission(s): 8214 Problem Description Speakless很早就想出国,现在他已经考完了所有需要的考试,准备了所有要准备的材料,于是,便需要去申请学校了.要申请国外的任何大学,你都要

01背包 Codeforces Round #267 (Div. 2) C. George and Job

题目传送门 1 /* 2 题意:选择k个m长的区间,使得总和最大 3 01背包:dp[i][j] 表示在i的位置选或不选[i-m+1, i]这个区间,当它是第j个区间. 4 01背包思想,状态转移方程:dp[i][j] = max (dp[i-1][j], dp[i-m][j-1] + sum[i] - sum[i-m]); 5 在两个for循环,每一次dp[i][j]的值都要更新 6 */ 7 #include <cstdio> 8 #include <cstring> 9 #i

01背包、完全背包、多重背包

参考(都有些错误):https://github.com/guanjunjian/Interview-Summary/blob/master/notes/algorithms/%E7%BB%8F%E5%85%B8%E7%AE%97%E6%B3%95/01%E8%83%8C%E5%8C%85.mdhttps://blog.csdn.net/na_beginning/article/details/62884939 #include <iostream> #include <sstream&