DP——背包问题复习

DP——背包问题复习

  • 01背包
    • 模板题
  • 完全背包
  • 多重背包
  • 分组背包

01背包问题

AcWing 2. 01背包问题

  • 思路:
    • 状态表示:f[i, j]表示从前i个物品中选,体积为j的方案集合,值为所有方案价值的最大值。
    • 状态计算:对于第i个物品只有两种操作,选or不选,所以状态f[i, j]只能有f[i-1, j-vi] + wi和f[i-1,j]两种状态转移而来。
    • 转移方程:f[i][j] = max(f[i - 1][j], f[i - 1][j - vi] + wi && j >= vi)
    • 状态初始化:起点状态和非法状态均初始化为0
  • 优化:从二维优化成一维
#include<iostream>

using namespace std;

const int N = 1100;

int f[N], n, m;

int main()
{
    cin >> n >> m;
    for(int i = 1; i <= n; i++)
    {
        int w, v;
        cin >> v >> w;
        for(int j = m; j >= v; j--)f[j] = max(f[j], f[j - v] + w);
    }
    cout << f[m];
    return 0;
}



完全背包问题

AcWing 3. 完全背包问题

  • 核心思路:
    • f[i][j] = max(f[i - 1][j], f[i-1][j-vi] + wi, f[i-1][j-2vi] + 2wi, …)
    • f[i][j - vi] = max(f[i - 1][j - vi], f[i - 1][j - 2vi] + wi, f[i - 1][j - 3vi] + 2wi , …)
    • f[i][j] = max(f[i - 1][j], f[i][j - vi] + wi]
#include<iostream>

using namespace std;

const int N = 1100;

int n, m, f[N];

int main()
{
    cin >> n >> m;
    for(int i = 1; i <= n; i++)
    {
        int v, w;
        cin >> v >> w;
        for(int j = v; j <= m; j++)f[j] = max(f[j], f[j - v] + w);
    }
    cout << f[m];
    return 0;
}



多重背包问题

AcWing 5. 多重背包问题 II

  • 核心思路:
    • 对于任意一个数a,把它分解为多个不同的2的指数次幂(x1, x2, …, xn和一个常数c之和,则0~a的所有数均可表示为这n+1个数的某个组合(可能会有两个组合的值相同,不过对答案无影响)
    • 同理将s分解,则多重背包问题转化为01背包问题
#include<iostream>

using namespace std;

const int N = 21000;

int w[N], v[N], f[N];
int n, m, cnt;

int main()
{
    cin >> n >> m;
    for(int i = 0; i < n; i++)
    {
        int a, b, s;
        cin >> a >> b >> s;
        int p = 1;
        while(p <= s)
        {
            ++cnt;
            v[cnt] = a * p;
            w[cnt] = b * p;
            s -= p;
            p *= 2;
            
        }
        if(s)
        {
            ++cnt;
            v[cnt] = a * s;
            w[cnt] = b * s;
        }
    }
    
    for(int i = 1; i <= cnt; i++)
        for(int j = m; j >= v[i]; j--)
            f[j] = max(f[j], f[j - v[i]] + w[i]);
    
    cout << f[m];
    return 0;
}



分组背包问题

AcWing 9. 分组背包问题

  • 思路:
    • 类比01背包问题,只是多了一层循环用来选择每个组中的某个物品
#include<iostream>

using namespace std;

const int N = 110;

int f[N], n, m;

int main()
{
    cin >> n >> m;
    for(int i = 1; i <= n; i++)
    {
        int cnt, v[N], w[N];
        cin >> cnt;
        for(int k = 1; k <= cnt; k++)cin >> v[k] >> w[k];
        for(int j = m; j >= 0; j--)
            for(int k = 1; k <= cnt; k++)
                if(j >= v[k])f[j] = max(f[j], f[j - v[k]] + w[k]);
    }
    cout << f[m];
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值