算法提高之动态规划:背包模型一

0、总览

在这里插入图片描述
在这里插入图片描述

1、多重背包问题(单调队列优化)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 20010;

int n, m;
//q队列  记录的是下标
int f[N], g[N], q[N];

int main()
{
    cin >> n >> m;
    for (int i = 0; i < n; i ++ )
    {
        int v, w, s;
        cin >> v >> w >> s;
        //将上一层的滚动数组存下来
        memcpy(g, f, sizeof f);
        //枚举余数
        for (int j = 0; j < v; j ++ )
        {
            int hh = 0, tt = -1;
            //枚举数值
            for (int k = j; k <= m; k += v)
            {
            //队头<左端点 出队 队头元素滑出滑动窗口
            //假设s=3 k=r+3v 滑动窗口是 [r,r+v,r+2v] 此时求的是f[r+3v]
            //求f[r+3v]需要得到r,r+v,r+2v时的最大值 则hh不需要抛出
            //假设q[hh]=r;
            //k=r+3v  k-3v=r q[hh]=r  r   q[hh]则不弹出
                if (hh <= tt && q[hh] < k - s * v) hh ++ ;
           //删除队尾元素
           //j是余数 g[q[tt]]队尾元素 g[k]新插入的元素
           //q[tt]-j/v*w  队尾元素减去几个w
           //(k-j)/v*w 新元素 减去几个w
           //最大值  递减数列  <=
           //很难算出w的具体数值,但是知道从r,r+v->j-V->j 每个之间相差w
     //r-0w,r+v-1w,利用相对数据找到最大值(此处的最大值是f[i-1,(j-xv)])
           //没加偏移量
            //假设s=3 k=r+3v 滑动窗口是 [r,r+v,r+2v] 此时求的是f[r+3v]
            //求f[r+3v]需要得到r,r+v,r+2v 还有f[i-1,r+3v]时的最大值 
     //在这种情况下,g[k]可以看作f[i-1,j](便于理解f[i-1,j] f[i-1,j-v])。
                while (hh <= tt && g[q[tt]] - (q[tt] - j) / v * w <= g[k] - (k - j) / v * w) tt -- ;
                q[ ++ tt] = k;
               //q[hh] 最大值的下标
               //g[q[hh]] f值   上一层的f+?w  ?=队头元素距离距离数值 含有多少个w 
               //此处的最大值是f[i-1,(j-xv)])没加偏移量。
               //对相对数值  需要加上偏移量才能变成f[k] 
                f[k] = g[q[hh]] + (k - q[hh]) / v * w;
            }
        }
    }

    cout << f[m] << endl;

    return 0;
}

在这里插入图片描述
在这里插入图片描述

2、采药(01)

在这里插入图片描述
在这里插入图片描述

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;
const int N = 1010;
int m, n;
int f[N];

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

3、装箱问题(01)

在这里插入图片描述

#include <iostream>
#include <algorithm>

using namespace std;

const int M = 20010;

int n, m;
int f[M];

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

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

    return 0;
}

在这里插入图片描述

4、宠物小精灵之收服(二维费用01)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1010, M = 510;

int n, V1, V2;
int f[N][M];

int main()
{
    cin >> V1 >> V2 >> n;
    for (int i = 0; i < n; i ++ )
    {
        int v1, v2;
        cin >> v1 >> v2;
        for (int j = V1; j >= v1; j -- )
        //因为k是消耗的体力值,体力值最大为100,消耗的体力值为100-1;
        //体力值为0就结束,固然消耗的体力值要比最大体力值小1
        //V2-1 皮卡丘的体积不为0
            for (int k = V2 - 1; k >= v2; k -- )
                f[j][k] = max(f[j][k], f[j - v1][k - v2] + 1);
    }
	//消耗的精灵球是V1,消耗的体力值是V2-1,时的捕捉小精灵最大数量
    cout << f[V1][V2 - 1] << ' ';
    //k是消耗的体力值,因此k比最大体力值小1
    int k = V2 - 1;
    while (k > 0 && f[V1][k - 1] == f[V1][V2 - 1]) k -- ;
    //V2-k 剩余的体力值  最大体力值-消耗体力值
    cout << V2 - k << endl;

    return 0;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值