poj3624----01bag(一维+(二维+滚动数组))

来源:互联网 发布:山东招宝万金网络 编辑:程序博客网 时间:2024/06/07 00:25

Charm Bracelet
Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 31755 Accepted: 14120

Description

Bessie has gone to the mall's jewelry store and spies a charm bracelet. Of course, she'd like to fill it with the best charms possible from the N (1 ≤ N ≤ 3,402) available charms. Each charm i in the supplied list has a weight Wi (1 ≤ Wi ≤ 400), a 'desirability' factor Di (1 ≤ Di ≤ 100), and can be used at most once. Bessie can only support a charm bracelet whose weight is no more than M (1 ≤ M ≤ 12,880).

Given that weight limit as a constraint and a list of the charms with their weights and desirability rating, deduce the maximum possible sum of ratings.

Input

* Line 1: Two space-separated integers: N and M
* Lines 2..N+1: Line i+1 describes charm i with two space-separated integers: Wi and Di

Output

* Line 1: A single integer that is the greatest sum of charm desirabilities that can be achieved given the weight constraints

Sample Input

4 61 42 63 122 7

Sample Output

23

题意:一共量为N块宝石,想要镶嵌最多W的重量的宝石

            下面给出在重量为W宝石,镶嵌相应宝石会得到相应宝石的魔法为D


一维dp的循环里面开始点和二维的不同


二维01 dp + 滚动数组

#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;int weight[4000],value[4000];int dp[3][13000];int main(){    int n,m;    //freopen("in.txt","r",stdin);    scanf("%d%d",&n,&m);    for(int i=0;i<n;i++)        scanf("%d%d",&weight[i],&value[i]);    for(int i=0;i<n;i++)        for(int j=0;j<=m;j++)            if(j>=weight[i])                dp[(i+1)%2][j]=max(dp[i%2][j],dp[i%2][j-weight[i]]+value[i]);            else                dp[(i+1)%2][j]=dp[i%2][j];    printf("%d\n",dp[n%2][m]);    return 0;}

其中第二层循环可以是

for(int j=m;j>=0;j--)

并且两层循环不可以互换



一维01dp

#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;int a[40000][3];int dp[40000];int main(){    int n,m;    scanf("%d%d",&n,&m);    for(int i=0;i<n;i++)        scanf("%d%d",&a[i][0],&a[i][1]);    for(int i=0;i<n;i++)        for(int j=m;j>=a[i][0];j--)            dp[j]=max(dp[j],dp[j-a[i][0]]+a[i][1]);    printf("%d\n",dp[m]);    return 0;}



如何理解二维降一维呢?

对于外层循环中的每一个i值,其实都是不需要记录的,在第i次循环时,所有的dp[0…v]都还未更新时,dp[j]还记录着前i-1个物品在容量为j时的最大价值,这样就相当于还记录着dp[i-1][j]和dp[i-1][j-vol[i]]+val[i]。

为什么要从v开始递减遍历?

我举个例子,假设一个物品GG价值1000,体积为2,那么假设我们按【0…..v】这个顺序遍历,那么在j=2时,dp[2] = max(dp[2], dp[0]+1000),那么dp[2] = 1000,当j=4时,dp[4]=max(dp[4], dp[2]+1000), dp[4] = 2000,这时我们再思考一下,GG将被放进背包两次!!,如果我们逆序遍历,就可以避免这种结果。


初始化的细节问题
我们看到的求最优解的背包问题题目中,事实上有两种不太相同的问法。有的题目要求“恰好装满背包”时的最优解,有的题目则并没有要求必须把背包装满。一种区别这两种问法的实现方法是在初始化的时候有所不同。
如果是第一种问法,要求恰好装满背包(推荐blog  :http://blog.csdn.net/summer__show_/article/details/51447328),那么在初始化时除了f[0]为0其它f[1..V]均设为正无穷负无穷,这样就可以保证最终得到的f[N]是一种恰好装满背包的最优解。
如果并没有要求必须把背包装满,而是只希望价格尽量大,初始化时应该将f[0..V]全部设为0。

为什么呢?可以这样理解:初始化的f数组事实上就是在没有任何物品可以放入背包时的合法状态。如果要求背包恰好装满,那么此时只有容量为0的背包可能被价值为0的nothing“恰好装满”,其它容量的背包均没有合法的解,属于未定义的状态,它们的值就都应该是-∞了。如果背包并非必须被装满,那么任何容量的背包都有一个合法解“什么都不装”,这个解的价值为0,所以初始时状态的值也就全部为0了。

0 0