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]转移过来。
    */
  • 相关阅读:
    Django开发个人博客网站
    Photoshop界面字体太小解决方案
    [Leetcode]第三题:无重复字符最长子串
    web网站服务(1)
    备份与恢复笔记和实验
    oracle事物和常用数据库对象笔记和实验
    Oracle配置管理实验
    Oracle配置管理笔记
    Oracle体系结构和用户管理实验
    Oracle数据库部署
  • 原文地址:https://www.cnblogs.com/xiehuazhen/p/12464732.html
Copyright © 2011-2022 走看看