• 01背包与完全背包


    01背包
    有一个体积为V的背包,有n个物品,每个物品都有体积vi和价值wi,在背包体积范围内,求能桌下的最大价值。

    这个问题中每个物品只能用一次。
    设dp[i][j]表示用前i个物品装体积为j的背包。
    那么第i个物品要么装要么不装:

    1、如果不装,第i个物品和没有一样,dp[i][j]=dp[i-1][j]
    2、如果装,减去第i个物品的体积,加上第i个物品的价值,那么它还是和没有一样。。dp[i][j]=dp[i-1][j-v[i]]+w[i];

    我们只需取这两种方案的最大值,就算是解决了。dp[i][j]=max(dp[i-1][j],dp[i-1][j-v[i]]+w[i]);

    时间复杂度是O(V*M),空间也是O(V*M)
    其实空间可以优化
    注意观察,可以发现每个状态dp[i][j]之和dp[i-1][]有关,什么i-2,i-3都没用了
    我们试着开一个一维的数组dp[M];
    一维难道不会覆盖掉原来的值么?
    会的,但我们优先覆盖不用的值。怎么说呢?就是我们每次只会用比j小的地方的值,比j大的地方是不用到的,所以我们只要j从后往前枚举,就不会冲突了。

    dp[j]=max(dp[j],dp[j-v[i]]+w[i]) [j=N->v[i]]

    for(int i= 1; i <= n; i++) {
    for (int j = m; j >= w[i]; j--) {
    dp[j] = max(dp[j], dp[j-w[i]]+v[i]);
    }
    }
    完全背包
    完全背包就是每种物品有无限个的背包
    这个时候我们的状态转移方程可以这么写:dp[i][j]=max(dp[i-1][j],dp[i][j-v[i]]+w[i]);
    看起来好像没区别啊?!
    真的么?
    仔细看看,i-1变成了i
    也就是说,选择了第i个物品后,并不是转到i-1,因为每个物品有无限个,所以还是转到了i
    状压一下,就是
    dp[j]=max(dp[j],dp[j-v[i]]+w[i]) 【j=v[i]->N】

    唯一的区别就是j枚举的方向反了过来
    for(int i= 1; i<= n; i++) {
    for (int j = w[i]; j <= m; j++) {
    dp[j] = max(dp[j], dp[j-w[i]]+v[i]);
    }
    }

  • 相关阅读:
    35 个手机和Web应用开发图标集
    20个创意404错误页面设计的启示
    31个不同种类的网站免费滑块巨大集合(PSD文件)
    18个伟大的搜索引擎设计者能够找到高品质的免费图标
    50 个独家免费图标集下载
    C语言对结构体何时用> , 何时用.
    GNU make manual 翻译(一)
    PostgreSQL 的 语法分析调用关系
    GNU make manual 翻译(二)
    PostgreSQL 的 target_list分析(七)
  • 原文地址:https://www.cnblogs.com/a863886199/p/8672465.html
Copyright © 2020-2023  润新知