POJ3624---01背包入门 dp+滚动数组+重复利用一维数组
2017-11-18 12:23
309 查看
题意:01背包入门题(入门必做)
思路:dp,用二维数组会MLE(超内存),由于每个状态只与前一状态有关,故可开滚动数组压缩空间,也可以重复利用一个一维数组。
dp[i][j]代表从前i个物品中选出总重量不超过j的物品时总价值的最大值。则
dp[i][j]=max{dp[i-1][j],dp[i-1][w[i]-j]+v[i]} (w[i]<=j)
dp[i][j]=dp[i-1][j] (w[i]>j)
边界控制:
dp[i][j]=0 (i==0||j==0)由于定义全局数组,所以在代码中不必再赋值。
本题作为dp背包问题的入门题,值得新手去做,如果觉得不能理解递推关系,滚动数组,重复利用一维数组…~
可以先把二维数组里的值一步一步给画出来(我看的挑战程序设计那本书上有这种图),然后你就会明白所以然了。可以打印下:(斜线代表取,直线代表不取。然后再用这个图理解下滚动数组和一维数组。测试数据为poj上的。)
![](https://oscdn.geek-share.com/Uploads/Images/Content/202005/10/2880d4e2328837703edefbe85c5e200b)
说下注意的问题:
第二个for循环,可以正序,也可以逆序,因为dp[i+1][…]里的东西都是从dp[i]中得出来的。
但是带来的问题就是内存超了。
滚动数组也是可以正序,可以逆序。
但是重复利用一维数组就必须要逆序了,因为得到后面的必须要用到前面的~~~这让你想起了什么???记得刚开始学程序设计的时候,老师让打印杨辉三角,说用一维数组打印试试~(实际上,杨辉三角也是动态规划问题咯)
说明2:
滚动数组:
当前状态都来源于上一个状态,所以这时候只需要两个数组就够了。拿经典的01背包问题来说,第二行只和第一行有关,第三行只和第二行有关……所以只需要两行就
可以了。当然,有的复杂的dp问题i和i-1,i-2有关,这时候要开三行数组,i%3
一维数组:
主要是顺序还是逆序的问题,如果当前状态来源于“上”和“左斜上”(01背包)那么要逆序了,自己一定要明白为什么要这样 , 如果当前状态来源于“←”和“↖”(完全背包)那就要顺序了。
如果当前状态来源于“←”,“↑”和“↖”,这时候就不能用一维数组来优化了,必须要用滚动数组。
说明3:
并非所有的问题都要去优化空间,有的要输出路径,这时候就不能压缩空间了,需要保留所有的数据。比如这两道题:
1 2
三种代码:(依次为原始二维数组,滚动二维数组,一维数组)
思路:dp,用二维数组会MLE(超内存),由于每个状态只与前一状态有关,故可开滚动数组压缩空间,也可以重复利用一个一维数组。
dp[i][j]代表从前i个物品中选出总重量不超过j的物品时总价值的最大值。则
dp[i][j]=max{dp[i-1][j],dp[i-1][w[i]-j]+v[i]} (w[i]<=j)
dp[i][j]=dp[i-1][j] (w[i]>j)
边界控制:
dp[i][j]=0 (i==0||j==0)由于定义全局数组,所以在代码中不必再赋值。
本题作为dp背包问题的入门题,值得新手去做,如果觉得不能理解递推关系,滚动数组,重复利用一维数组…~
可以先把二维数组里的值一步一步给画出来(我看的挑战程序设计那本书上有这种图),然后你就会明白所以然了。可以打印下:(斜线代表取,直线代表不取。然后再用这个图理解下滚动数组和一维数组。测试数据为poj上的。)
说下注意的问题:
第二个for循环,可以正序,也可以逆序,因为dp[i+1][…]里的东西都是从dp[i]中得出来的。
但是带来的问题就是内存超了。
滚动数组也是可以正序,可以逆序。
但是重复利用一维数组就必须要逆序了,因为得到后面的必须要用到前面的~~~这让你想起了什么???记得刚开始学程序设计的时候,老师让打印杨辉三角,说用一维数组打印试试~(实际上,杨辉三角也是动态规划问题咯)
说明2:
滚动数组:
当前状态都来源于上一个状态,所以这时候只需要两个数组就够了。拿经典的01背包问题来说,第二行只和第一行有关,第三行只和第二行有关……所以只需要两行就
可以了。当然,有的复杂的dp问题i和i-1,i-2有关,这时候要开三行数组,i%3
一维数组:
主要是顺序还是逆序的问题,如果当前状态来源于“上”和“左斜上”(01背包)那么要逆序了,自己一定要明白为什么要这样 , 如果当前状态来源于“←”和“↖”(完全背包)那就要顺序了。
如果当前状态来源于“←”,“↑”和“↖”,这时候就不能用一维数组来优化了,必须要用滚动数组。
说明3:
并非所有的问题都要去优化空间,有的要输出路径,这时候就不能压缩空间了,需要保留所有的数据。比如这两道题:
1 2
三种代码:(依次为原始二维数组,滚动二维数组,一维数组)
#include<iostream> #include<algorithm> using namespace std; int dp[3500][13000];//0 int w[3500], v[3500]; int main() { int N, M; cin >> N >> M; for (int i = 1; i <= N; i++) cin >> w[i] >> v[i]; for(int i=1;i<=N;i++) for (int j = 0; j <= M; j++) { if (j < w[i])dp[i][j] = dp[i - 1][j]; else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + v[i]); } cout << dp [M]; system("pause"); }
#include<iostream> #include<algorithm> using namespace std; int dp[2][13000];//0 int w[3500], v[3500]; int main() { int N, M; cin >> N >> M; for (int i = 1; i <= N; i++) cin >> w[i] >> v[i]; for(int i=1;i<=N;i++) for (int j = 0; j <= M; j++) { if (j < w[i])dp[i%2][j] = dp[(i - 1)%2][j]; else dp[i % 2][j] = max(dp[(i - 1) % 2][j], dp[(i - 1) % 2][j - w[i]] + v[i]); } cout << dp[N%2][M]; system("pause"); }
#include<iostream> #include<algorithm> using namespace std; int dp[13000];//0 int w[3500], v[3500]; int main() { int N, M; cin >> N >> M; for (int i = 1; i <= N; i++) cin >> w[i] >> v[i]; for(int i=1;i<=N;i++) for (int j = M; j >= w[i]; j--) //j >= w[i]这个结束条件是从 j>0和下面的if(j >= w[i])语句得来的。 { dp[j] = max(dp[j], dp[j - w[i]] + v[i]); } cout << dp[M]; system("pause"); }
相关文章推荐
- POJ 3624 【DP入门之01背包】
- POJ 3624- Charm Bracelet(01背包 滚动数组)
- dp中滚动数组的应用:01背包、POJ 1159 Palindrome、多段图路径问题
- POJ-3624 Charm Bracelet (01背包 入门题)
- poj 3624 Charm Bracelet(01背包入门题)
- POJ 3624 01背包入门题目
- POJ 3624 Charm Bracelet(DP动态规划+滚动数组)
- poj1159--Palindrome(dp:最长公共子序列变形 + 滚动数组)
- poj 3624 Charm Bracelet(0-1背包~DP~)
- UVA 562 【DP入门之01背包】
- 01背包空间优化的形式(滚动数组)(2955)
- poj 3628 Bookshelf 2(01背包入门或者dfs)
- Happy Matt Friends(利用滚动数组优化数组空间的DP)
- POJ 1837 Balance(01背包变形, 枚举DP)
- 01背包问题-状态d[i][j],f[i][j],滚动数组--java实现
- POJ 3628 Bookshelf2 / POJ 3624 Charm Bracelet / POJ 1384 初涉01背包与完全背包
- POJ 3624 Charm Bracelet (01)(背包入门)
- POJ - 3624 (01背包问题)(动态规划-滚动数组)
- POJ-3624-Charm Bracelet-简单0/1背包、动态规划、DP
- POJ 1159 Palindrome(区间DP/最长公共子序列+滚动数组)