zoukankan      html  css  js  c++  java
  • hihocoder1043 完全背包

    完全背包问题跟01背包问题的区别在于:对每种物品,在01背包中可以选取0个或者1个,而在完全背包中,每种物品都可以选取任意多个。

    状态定义:

    dp[i][j]表示:解决了第0~i中物品的选取问题,已消耗容量为j时,获得的最大价值。

    状态转移:

    这里的状态转移有两种写法,第一种写法较容易理解,第二中写法理解起来要稍微难一点。

    第一种写法:

    dp[i][j] = max(dp[i-1][j], dp[i-1][j-k*w[i]]+k*v[i]), (k>=0且k*w[i]<=j)

    第二种写法:

    当w[i]>j时,已消耗容量j比w[i]还小,这种情况显然是第i个物品选取0个的情况,此时显然dp[i][j] = dp[i-1][j];

    当w[i]<=j时,dp[i][j] = max(dp[i-1][j], dp[i][j-w[i]]+v[i]), 因为这时候dp[i][j]无非只可能由两种情况之一转换而来,第一种情况就是第i个物品选取0个,第二种情况是“在第i个物品已经选取了若干的情况下,再选取了一个 ”,为什么可以这样做呢?因为我们的计算顺序是先计算较小的j的情况再计算较大的j的情况,所以在计算dp[i][j]的时候,dp[i][j-w[i]]已经计算过了,可以直接用。

    我的代码:

    采用第一种状态转移:

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 using namespace std;
     5 
     6 #define MAXN 501
     7 #define MAXM 100005
     8 
     9 int dp[MAXN][MAXM], w[MAXN], v[MAXN];
    10 
    11 int main()
    12 {
    13     int n, m, ans;
    14     while(scanf("%d%d", &n, &m)!=EOF)
    15     {
    16         for(int i=0; i<n; ++i)
    17             scanf("%d%d", &w[i], &v[i]);
    18         
    19         memset(dp[0], 0, sizeof(dp[0]));
    20         for(int k=1; k*w[0]<=m; ++k)
    21             dp[0][k*w[0]] = v[0]*k;
    22         for(int i=1; i<n; ++i)
    23         {
    24             for(int j=0; j<=m; ++j)
    25             {
    26                 dp[i][j] = dp[i-1][j];
    27                 for(int k=1; k*w[i]<=j; ++k)
    28                     dp[i][j] = max(dp[i][j], dp[i-1][j-k*w[i]]+k*v[i]);
    29             }    
    30         }
    31         ans = 0;
    32         for(int i=0; i<=m; ++i) ans = max(ans, dp[n-1][i]);    
    33         printf("%d
    ", ans);    
    34     }
    35     return 0;
    36 }

    采用第二种状态转移:

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 using namespace std;
     5 
     6 #define MAXN 501
     7 #define MAXM 100005
     8 
     9 int dp[MAXN][MAXM], w[MAXN], v[MAXN];
    10 
    11 int main()
    12 {
    13     int n, m, ans;
    14     while(scanf("%d%d", &n, &m)!=EOF)
    15     {
    16         for(int i=0; i<n; ++i)
    17             scanf("%d%d", &w[i], &v[i]);
    18         
    19         memset(dp[0], 0, sizeof(dp[0]));
    20         for(int k=1; k*w[0]<=m; ++k)
    21             dp[0][k*w[0]] = v[0]*k;
    22         for(int i=1; i<n; ++i)
    23         {
    24             for(int j=0; j<=m; ++j)
    25             {
    26                 if(w[i]>j) dp[i][j] = dp[i-1][j];
    27                 else
    28                 {
    29                     dp[i][j] = max(dp[i-1][j], dp[i][j-w[i]]+v[i]);
    30                 }
    31             }    
    32         }
    33         ans = 0;
    34         for(int i=0; i<=m; ++i) ans = max(ans, dp[n-1][i]);    
    35         printf("%d
    ", ans);    
    36     }
    37     return 0;
    38 }

    采用第二种状态转移+优化空间复杂度:

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 using namespace std;
     5 
     6 #define MAXN 501
     7 #define MAXM 100005
     8 
     9 int dp[MAXM], w[MAXN], v[MAXN];
    10 
    11 int main()
    12 {
    13     int n, m, ans;
    14     while(scanf("%d%d", &n, &m)!=EOF)
    15     {
    16         for(int i=0; i<n; ++i)
    17             scanf("%d%d", &w[i], &v[i]);
    18         
    19         memset(dp, 0, sizeof(dp));
    20         for(int i=0; i<n; ++i)
    21         {
    22             for(int j=0; j<=m; ++j)
    23             {
    24                 if(j>=w[i]) dp[j] = max(dp[j], dp[j-w[i]]+v[i]);
    25             }    
    26         }
    27         ans = 0;
    28         for(int i=0; i<=m; ++i) ans = max(ans, dp[i]);    
    29         printf("%d
    ", ans);    
    30     }
    31     return 0;
    32 }

    题目来源:http://hihocoder.com/problemset/problem/1043

  • 相关阅读:
    Android开发 ViewConfiguration View的配置信息类
    Android 开发 倒计时功能 转载
    Android 开发 关于7.0 FileUriExposedException异常 详解
    Android 开发 实现文本搜索功能
    Android 开发 Activity里获取View的宽度和高度 转载
    Android 开发 存储目录的详解
    Android 开发 Fresco框架点击小图显示全屏大图实现 ZoomableDraweeView
    Android 开发 将window变暗
    Android 开发 DisplayMetrics获取Android设备的屏幕高宽与其他信息
    Android 开发 DP、PX、SP转换详解
  • 原文地址:https://www.cnblogs.com/pczhou/p/4295368.html
Copyright © 2011-2022 走看看