完全背包问题和优化

11 篇文章 0 订阅

完全背包问题

题意

  • 选取的物品无限
  • 求价值最大值

分析图解

难点:状态计算——第i个物品选(0 - k)个。那么k*v【i】 <= 背包剩余空间

  • 第i个物品,选k个
  • 那么需要加上 k个物品的价值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-971czOK3-1591071454311)(完全背包问题.assets/1588993577256.png)]

朴素的算法

/*
f[i - 1][j] 一个都不选 k == 0
f[i - 1][j - v[i] * k] + w[i] * k 选1 ~ k个 1 <= k <= s[i]
*/

#include <iostream>

using namespace std;

const int N = 1010;

int v[N], w[N];
int f[N][N];

int main ()
{
    int n, m;
    cin >> n >> m;

    for(int i = 1 ; i <= n ; i ++ ) cin >> v[i] >> w[i];

    for(int i = 1 ; i <= n ; i ++ )
        for(int j = 1 ; j <= m ; j ++ )
            for(int k = 0 ; k * v[i] <= j ; k ++ )/有k个可以选
                f[i][j] = max(f[i][j], f[i - 1][j - v[i] * k] + w[i] * k);

    cout << f[n][m] << endl;

    return 0;
}

优化图解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7kaUm7eH-1591071454317)(../图库/1590666216829.png)]

优化后的代码

#include <iostream>

using namespace std;

const int N = 1010;

int v[N], w[N];
int f[N][N];

int main ()
{
    int n, m;
    cin >> n >> m;

    for(int i = 1 ; i <= n ; i ++ ) cin >> v[i] >> w[i];

    for(int i = 1 ; i <= n ; i ++ )
        for(int j = 1 ; j <= m ; j ++ )
        {
            f[i][j] = f[i - 1][j];//如果不选i,那么必须从前一项继承下来
            if(j >= v[i]) f[i][j] = max(f[i - 1][j], f[i][j - v[i]] + w[i]);
        }

    cout << f[n][m] << endl;

    return 0;
}

优化状态转移方程 + 降维优化

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FkRHDtzs-1591071454323)(../图库/1590666232909.png)]

#include <iostream>

using namespace std;

const int N = 1010;

int v[N], w[N];
int f[N];

int main ()
{
    int n, m;
    cin >> n >> m;

    for(int i = 1 ; i <= n ; i ++ ) cin >> v[i] >> w[i];

    for(int i = 1 ; i <= n ; i ++ )
        // //因为此时,状态和同层的 i 相关,那么如果状态压缩,那么可以从小到大循环
        for(int j = v[i] ; j <= m ; j ++ )
        {
            f[j] = max(f[j], f[j - v[i]] + w[i]);
        }

    cout << f[m] << endl;

    return 0;
}
  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值