您的位置:首页 > 其它

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上的。)


说下注意的问题:

第二个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");
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: