zoukankan      html  css  js  c++  java
  • 背包九讲之二:完全背包问题:一个物品允许选多次

    有 N 件物品和一个容量是 V 的背包。每种物品都有无限件可用。
    第 i 件物品的体积是 vi,价值是 wi。
    求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
    输出最大价值。
    输入格式
    第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。
    接下来有 N 行,每行两个整数 vi,wi用空格隔开,分别表示第 i 件物品的体积和价值。
    输出格式
    输出一个整数,表示最大价值。
    数据范围
    0<N,V≤1000
    0<vi,wi≤1000
    输入样例
    4 5
    1 2
    2 4
    3 4
    4 5
    输出样例
    10
     代码如下:
     1 #include<iostream>
     2 #include<algorithm>
     3 using namespace std;
     4 /*
     5 f[i][j]表示只看前i个物品,总体积是j的情况下,总价值最大是多少
     6 result = f[n]f[v]
     7 1.不选第i个物品,f[i][j]=f[i-1][j];
     8 2.选第i个物品,f[i][j]=f[i-1][j-k*v[i]]+k*w[i](v[i]是体积,w[i]是价值,k是物品最大个数)
     9 f[0][0]=0;
    10 */
    11 const int array_size = 1001;
    12 int f[array_size][array_size], v[array_size], w[array_size], N, V;
    13 int main() {
    14     cin >> N >> V;
    15     for (int i = 1; i <= N; ++i) {
    16         cin >> v[i] >> w[i];
    17         for (int j = 0; j <= V; ++j) {
    18             f[i][j] = f[i - 1][j];
    19             for (int k = 1; k * v[i] <= j; ++k)
    20                 f[i][j] = max(f[i][j], f[i - 1][j - k * v[i]] + k * w[i]);
    21         }
    22 
    23     }
    24     cout << f[N][V];
    25 }
    优化后如下:
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int array_size = 1001;
    int f[array_size], v[array_size], w[array_size], N, V;
    int main() {
        cin >> N >> V;
        for (int i = 1; i <= N; ++i) {
            cin >> v[i] >> w[i];
            /*
            相当于01背包问题换了j的遍历顺序,结果就是第i轮(前i个物品)
            中,先算f[j-v[i]],再算f[j]
            数学归纳法证明优化后算法成立:
            1、前1个物品中:f[1]=2,f[2]=4,f[3]=6,f[4]=8,f[5]=10,显然f[j]都是正确的。
            2、假设在前i-1个物品中,f[j]都是正确的。
            3、前i个物品中,对于某个j而言,如果最优解包含k个v[i],则一定会枚举到f[j-k*v[i]]
            f[j-k*v[i]]是如何得到的呢?f[j-k*v[i]]=max{f[j-k*v[i]],f[j-k*v[i]-v[i]]+w[i]}
            (由于j正序,f[j-k*v[i]]为前i-1个物品的值,f[j-k*v[i]-v[i]]为前i个物品的值)
            最后会传递到max{f[v[i]],f[0]+w[i]}处。因为f[v[i]]一定正确(2中已假设前i-1个物品
            中的f[j]全都正确),f[0]一定正确(=0),w[i]一定正确,所以max{f[v[i]],f[0]+w[i]}
            一定正确=>f[j-k*v[i]]一定正确=>f[j]一定正确。
            综上,证明成立。
            */
            for (int j = v[i]; j <= V; ++j)
                f[j] = max(f[j], f[j -v[i]] + w[i]);
                
        }
        cout << f[V];
    }
    /*
    若是要求物品恰好装满背包时的最大价值,只需
    初始化时将f[0]置0,f[1]-f[V]都置-INF就可以了。
    确保所有状态都是由f[0]转移过来。
    */
  • 相关阅读:
    Linux之文件处理命令
    Linux基础命令
    rip实验
    Linux基础之磁盘分区
    mysql安装
    centos Apache、php、mysql默认安装路径
    You probably tried to upload too large file. Please refer to documentation for ways to workaround this limit.
    Wrong permissions on configuration file, should not be world writable!
    机器会学习么 学习总结
    实验 5 Spark SQL 编程初级实践
  • 原文地址:https://www.cnblogs.com/xiehuazhen/p/12464732.html
Copyright © 2011-2022 走看看