多重背包问题 II(Acwing 5,二进制优化多重背包 + 单调队列优化多重背包)

一.题目链接:

多重背包问题 II

二.题目大意:

多重背包

三.分析:

做个笔记,偷笑.

大佬的具体分析

立下 flag:这次我要学好 DP!!!

四.代码实现:

二进制优化

#include <bits/stdc++.h>
using namespace std;

const int M = (int)2e3;

int dp[M + 5];

struct node
{
    int v, w;
};
vector <node> vec;

int main()
{
    int n, m;
    cin >> n >> m;
    for(int i = 1, v, w, s; i <= n; ++i)
    {
        cin >> v >> w >> s;
        for(int j = 1; s >= j; j<<= 1)
        {
            s -= j;
            vec.push_back({v * j, w * j});
        }
        if(s)   vec.push_back({v * s, w * s});
    }
    
    for(auto i: vec)
    {
        for(int j = m; j >= i.v; --j)
        {
            dp[j] = max(dp[j], dp[j - i.v] + i.w);
        }
    }
    cout << dp[m] << "\n";
    
    return 0;
}

单调队列优化

#include <bits/stdc++.h>
using namespace std;

const int M = (int)2e4;
const int inf = 0x3f3f3f3f;

int q[M + 5];
int dp[M + 5];

int cal(int u, int k, int v, int w)
{
    return dp[u + k * v] - k * w;
}

int main()
{
    int n, m;
    scanf("%d %d", &n, &m);
    memset(dp, -inf, sizeof(dp));
    dp[0] = 0;
    for(int i = 1, v, w, c; i <= n; ++i)
    {
        scanf("%d %d %d", &v, &w, &c);
        for(int u = 0; u < v; ++u)
        {
            int l = 1, r = 0;
            int mx = (m - u) / v;
            for(int k = mx - 1; k >= max(mx - c, 0); --k)
            {
                while(l <= r && cal(u, k, v, w) >= cal(u, q[r], v, w))   --r;
                q[++r] = k;
            }
            for(int p = mx; p >= 0; --p)
            {
                while(l <= r && q[l] > p - 1)   ++l;
                if(l <= r)  dp[u + p * v] = max(dp[u + p * v], p * w + cal(u, q[l], v, w));
                if(p - 1 - c >= 0)
                {
                    while(l <= r && cal(u, p - 1 - c, v, w) >= cal(u, q[r], v, w))  --r;
                    q[++r] = p - 1 - c;
                }
            }
        }
    }
    int ans = 0;
    for(int i = 1; i <= m; ++i) ans = max(ans, dp[i]);
    printf("%d\n", ans);
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值