zoukankan      html  css  js  c++  java
  • 背包问题

    一、01背包

    给你一个容量为W的书包,一些体积(重量)为wi,价值为vi的东西,每个东西只有放与不放两种选择。

    经典例题:HDU 2602

    http://acm.hdu.edu.cn/showproblem.php?pid=2602

    题解:背包容量为V,有N件物品,已知每件物品的体积(重量)与价值,求最大价值。

    代码:

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<cmath>
     5 #include<algorithm>
     6 #include<stack>
     7 #define ll long long
     8 using namespace std;
     9 const int N = 1005;
    10 const int mod = 1e9 + 7;
    11 int dp[N][N], v[N], w[N];
    12 
    13 int main()
    14 {
    15     std::ios::sync_with_stdio(false);
    16     int T;
    17     cin >> T;
    18     while(T--){
    19         int n, V;
    20         memset(dp, 0, sizeof(dp));
    21         
    22         cin >> n >> V;
    23         for(int i = 1; i <= n; i++){
    24             cin >> v[i];
    25         }
    26         for(int i = 1; i <= n; i++){
    27             cin >> w[i];
    28         }
    29         //dp[i][j]表示在前i个物品中,总重量不超过j的总价值
    30         for(int i = 1; i <= n; i++){
    31             for(int j = 0; j <= V; j++){//顺序  从0到V
    32                 if(j < w[i]){
    33                     dp[i][j] = dp[i - 1][j];//放不下该物品,价值不变
    34                 }
    35                 else {
    36                     dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + v[i]);//放得下,求最大
    37                 }
    38             }
    39         }
    40         
    41         cout << dp[n][V] << endl;
    42     }
    43     return 0;
    44 }

    二、完全背包

    给你一个书包,和一些物品,物品价值和体积(重量)已知,数量无数,可以随便放。

    经典例题:HDU 1114

    http://acm.hdu.edu.cn/showproblem.php?pid=1114

    题解:一个存钱罐重a,装满钱重b,给你一些硬币的价值和重量,求最大价值。

    代码:

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<cmath>
     5 #include<algorithm>
     6 #include<queue>
     7 #define ll long long
     8 using namespace std;
     9 
    10 const int N = 10005;
    11 const int inf = 0x3f3f3f3f;
    12 
    13 int main()
    14 {
    15     int T;
    16     cin >> T;
    17     
    18     while(T--)
    19     {
    20         int a, b, m;
    21         int dp[N], v[N], w[N];//dp[j]表示在重量不超过j的情况下的最大价值
    22         memset(dp, inf, sizeof(dp));
    23         dp[0] = 0;
    24         
    25         cin >> a >> b >> m;
    26         
    27         for(int i = 0; i < m; i++)
    28         {
    29             cin >> v[i] >> w[i];
    30         }
    31         
    32         for(int i = 0; i < m; i++)
    33         {
    34             for(int j = w[i]; j <= b - a; j++)
    35             {
    36                 dp[j] = min(dp[j], dp[j - w[i]] + v[i]);
    37             }
    38         }
    39         
    40         if(dp[b - a] == inf)
    41             cout << "This is impossible." << endl;
    42         else
    43             cout << "The minimum amount of money in the piggy-bank is " << dp[b - a] << '.' << endl;
    44         
    45     }
    46     return 0;
    47 }

    三、多重背包

    给你一个书包,物品的价值和重量已知,每种物品的数量有限定且不一样。

    可以转化成01背包和完全背包问题求解。

    经典例题:HDU 2844

    http://acm.hdu.edu.cn/showproblem.php?pid=2844

    题解:给你几种硬币的价值和数量,求他们能组成多少种价值。

    代码:

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<cmath>
     5 #include<algorithm>
     6 #include<queue>
     7 #define ll long long
     8 using namespace std;
     9 
    10 const int N = 100005;
    11 const int inf = 0x3f3f3f3f;
    12 int dp[N];
    13 int v[N], num[N];
    14 
    15 void CompletePack(int v, int w, int bag) //完全背包 
    16 {
    17     for(int i = w; i <= bag; i++) // 顺序 
    18     {
    19         dp[i] = max(dp[i], dp[i - w] + v);
    20     }
    21 }
    22 
    23 void ZeroOnePack(int v, int w, int bag) //01背包 
    24 {
    25     for(int i = bag; i >= w; i--) //逆序  
    26     {
    27         dp[i] = max(dp[i], dp[i - w] + v);
    28     }
    29 }
    30 
    31 void MultiplePack(int v, int w, int count, int limit)//多重背包 
    32 {
    33     if(w * count >= limit)//背包足够大,转化为完全背包问题 
    34     {
    35         CompletePack(v, w, limit);
    36         return;
    37     }
    38     else//转化为01背包 
    39     {
    40         int k = 1;
    41         while(k <= count)
    42         {
    43             ZeroOnePack(k * v, k * w, limit);
    44             count -= k;
    45             k *= 2;//采用二进制思想 
    46         }
    47         ZeroOnePack(count * v, count * w, limit);
    48         return;
    49     }
    50 }
    51 
    52 int main()
    53 {
    54     std::ios::sync_with_stdio(false); 
    55 
    56     int n, m;
    57     while(cin >> n >> m && n && m)
    58     {
    59         memset(dp, -inf, sizeof(dp));
    60         dp[0] = 0;
    61         
    62         for(int i = 0; i < n; i++)
    63         {
    64             cin >> v[i];
    65         }
    66         for(int i = 0; i < n; i++)
    67         {
    68             cin >> num[i];
    69         }
    70         
    71         for(int i = 0; i < n; i++)
    72         {
    73             MultiplePack(v[i], v[i], num[i], m);
    74         }
    75         
    76         int ans = 0;
    77         for(int i = 1; i <= m; i++)
    78         {
    79             if(dp[i] > 0)
    80                 ans++;
    81         }
    82         
    83         cout << ans << endl;
    84         
    85     }
    86     return 0;
    87 }
  • 相关阅读:
    poj 2482 Stars in Your Window + 51Nod1208(扫描线+离散化+线段树)
    bzoj 1036: [ZJOI2008]树的统计Count (树链剖分+线段树 点权)
    树链剖分+线段树 单点修改 区间求和 模板
    bzoj 2124 等差子序列 (线段树维护hash)
    hdu 5638 Toposort (拓扑排序+线段树)
    hdu 5195 DZY Loves Topological Sorting (拓扑排序+线段树)
    Codeforces Round #250 (Div. 1) D. The Child and Sequence(线段树)
    hive 显示当前数据库名
    【Linux】ssh-keygen 的使用方法及配置 authorized_key s两台linux机器相互认证
    python email 模块
  • 原文地址:https://www.cnblogs.com/xiaohanghuo/p/11357184.html
Copyright © 2011-2022 走看看