• dp--01背包--Charm Bracelet


    Charm Bracelet

    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

    首先我们要明白i,j,dp[i][j]都分别代表着什么
    i:表示从1~i个物品里取
    j:表示此时的最大容积
    dp[i][j]:表示在1~i个物品里选取,每个物品只选择一次(限于01背包),且不超过j的容积,问所能得到的最大价值
    得出一个转移方程f[i][j] = max(f[i][j], f[i - 1][j - c[i]] + w[i])
    即在选取这个物品和不选这个物品中选择一个最大的
    最后我们要输出的就是dp[n][m]表示在n个物品中,容积不超出m的最大价值
     1 #include <cstdio>
     2 #include <iostream>
     3 #include <algorithm>
     4 using namespace std;
     5 int dp[4000][12000];
     6 int w[1000],c[1000];
     7 int main()
     8 {
     9     int n,m;
    10     scanf ("%d%d",&n,&m);
    11     for (int i =1 ;i<= n;i++)
    12     {
    13         scanf ("%d%d",&w[i],&c[i]);
    14     }
    15     for (int i = 1;i <= n;i++)
    16     {
    17         for (int j = 0;j <= m;j++)
    18         {
    19             dp[i][j] = dp[i-1][j];
    20             if (j-w[i]>=0)
    21             {
    22                 dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+c[i]);
    23                 
    24             }
    25         
    26         }    
    27     //    cout<<dp[i][m]<<endl;
    28     }
    29     cout<<dp[n][m];
    30     return 0;
    31 }
    先考虑上面讲的基本思路如何实现,肯定是有一个主循环i=1..N,每次算出来二维数组f[0..V]的所有值。那么,如果只用一个数组f[0..V],能不能保证第i次循环结束后f[v]中表示的就是我们定义的状态f[v]呢?f[v]是由f[v]和f[v-c]两个子问题递推而来,能否保证在推f[v]时(也即在第i次主循环中推f[v]时)能够得到f[v]和f[v-c]的值呢?事实上,这要求在每次主循环中我们以v=V..0的顺序推f[v],这样才能保证推f[v]时f[v-c]保存的是状态f[v-c]的值。伪代码如下:
    for i=1..N
    for v=V..0
    f[v]=max{f[v],f[c]+w};
    其中的f[v]=max{f[v],f[c]}一句恰就相当于我们的转移方程f[v]=max{f[v],f[c]},因为现在的f[c]就相当于原来的f[c]。如果将v的循环顺序从上面的逆序改成顺序的话,那么则成了f[v]由f[c]推知,与本题意不符
     1 #include<iostream>
     2 using namespace std;
     3 int f[20000];
     4 int main()
     5 {
     6     int  n,v;
     7     int w[20000], c[20000];
     8     cin >> n >> v;
     9     for(int i = 1; i <= n; ++i)
    10         cin >> w[i] >>c[i];
    11     for(int i = 1; i <= n; ++i){
    12         for (int j=v ;j>=w[i] ; j--){
    13                 f[j] = max(f[j], f[j - w[i]] + c[i]);
    14         }
    15     }
    16         cout << f[v]<<endl;
    17     return 0;
    18 }


  • 相关阅读:
    ACM——Points on Cycle
    ACM——A Simple Problem with Integers(线段树的精华版)
    HDU2524——矩形A+B
    ACM——Hero(类似贪心算法)
    用N个三角形最多可以把平面分成几个区域——acm
    ACM——敌兵布阵(经典的线段树)
    ACM——I Hate It(线段树的进化版)
    ACM——今年暑假不AC
    ACM题目Who's in the Middle
    内部排序算法
  • 原文地址:https://www.cnblogs.com/very-beginning/p/12039147.html
Copyright © 2020-2023  润新知