zoukankan      html  css  js  c++  java
  • POJ3624 0-1背包(dp+滚动数组)

    Charm Bracelet
    Time Limit: 1000MS   Memory Limit: 65536K
    Total Submissions: 47440   Accepted: 20178

    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 6
    1 4
    2 6
    3 12
    2 7

    Sample Output

    23

     

    如果用dp[n][m]:前n个物品不超过体积m的最大价值,状态转移方程为:

    dp[i][j] = 0(i==0orj==0)//没有物品,背包体积再大的最大价值也是0;再多物品,背包体积为0都塞不下。

    dp[i][j]=dp[i-1][j](j<d[i])//当前背包塞不下第i个物品,最大价值和第i-1个物品不大于体积j的最大价值是一样的。

    dp[i][j]=max(dp[i-1][j],dp[i-1][j-d[i]]+w[i])//当前背包若能装下第i个物品,那么就在装第i个物品后的最大价值和不装第i个物品的最大价值中取最大值

    但由于N和M的范围太大,开二维数组会爆内存,分析求解过程发现求解dp[i][j]时只与它上一行的正上方和上一行左边的某个值有关,也就是只用到了它上面那行,可以用一个滚动的一维数组求解,把新值放到上面的位置,但要注意顺序必须是从右到左,不然会覆盖掉有用的值。

     1 #include<iostream>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 int main()
     6 {
     7     int n, m;
     8     int d[13010], w[13010];
     9     int dp[13010];//因为求解该行时只与上一行有关,所以可以用滚动数组,dp[j]表示前i个物品在不超过体积j的最大价值
    10     cin >> n >> m;
    11     for (int i = 1; i <= n; ++i)
    12     {
    13         cin >> d[i] >> w[i];
    14     }
    15     memset(dp, 0, sizeof(dp));
    16     for (int i = 1; i <= n; ++i)
    17     {
    18         for (int j = m; j >= 1; --j)//从右往左求解,把新求出的值保存在上面的位置,因为被覆盖的值只与它下面和下一行的右边有关
    19         {
    20             if (j >= d[i])
    21                 dp[j] = max(dp[j], dp[j - d[i]] + w[i]);
    22             else       //如果j-d[i]<0,说明当前背包的容量不够放第i个物品,那放前i个物品的最大价值与放前i-1个物品的最大价值是相等的,
    23                 break;//又因为从右往左求值,左边的j只会更小,因此可跳过节省时间
    24                         
    25         }
    26     }
    27     cout << dp[m] << endl;
    28     return 0;
    29 }
  • 相关阅读:
    2021NUAA暑假集训 Day3 题解
    2021NUAA暑假集训 Day2 题解
    2021NUAA暑期模拟赛部分题解
    CodeForces 1038D Slime
    UVA 11149 Power of Matrix
    UVA 10655 Contemplation! Algebra
    UVA 10689 Yet another Number Sequence
    HDU 4549 M斐波那契数列
    HDU 4990 Reading comprehension
    CodeForces 450B Jzzhu and Sequences
  • 原文地址:https://www.cnblogs.com/knmxx/p/9531340.html
Copyright © 2011-2022 走看看