多重背包问题与优化(裸题)(二)

简介: 多重背包问题与优化(裸题)

多重背包问题 II

题目要求

题目描述:

image.png

输入格式:

image.png

输出格式:

输出一个整数,表示最大价值。

数据范围:

image.png

输入样例:

4 5
1 2 3
2 4 1
3 4 3
4 5 2

输出样例:

10

思路分析

image.png

#include <iostream>
using namespace std;
int main()
{
    int i, cnt = 1, temp = 0;
    for (i = 1; temp <= 2000; i ++ )
    {
        temp += cnt;
        cnt *= 2;
    }
    cout << i << endl;
    return 0;
}

运行结果为:12 ,即我们需要开的数组大小就为:12 × 1000 + 10 = 12010

代码

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2010, M = 12010, K = 1010;
int v[M], w[M];
int f[K][N];
int main()
{
    int n, m;
    cin >> n >> m;
    int cnt = 0;
    for (int i = 1; i <= n; i ++ )
    {
        int v1, w1, s;
        cin >> v1 >> w1 >> s;
        int t = 1;
        while (t <= s)
        {
            cnt ++;
            v[cnt] = t * v1;
            w[cnt] = t * w1;
            s -= t;
            t *= 2;
        }
        if (s)
        {
            cnt ++;
            v[cnt] = s * v1;
            w[cnt] = s * w1;
        }
    }
    n = cnt;
    for (int i = 1; i <= n; i ++ )
        for (int j = 0; j <= m; j ++ )
        {
            f[i][j] = f[i - 1][j];
            if (j >= v[i]) f[i][j] = max (f[i - 1][j], f[i - 1][j - v[i]] + w[i]);
        }
    cout << f[n][m] << endl;
    return 0;
}

代码优化

既然是转换为了 01背包问题,故我们可以使用 01背包问题优化的思维去优化我们的空间(倒着for循环体积)

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2010, M = 12010;
int v[M], w[M];
int f[N];
int main()
{
    int n, m;
    cin >> n >> m;
    int cnt = 0;
    for (int i = 1; i <= n; i ++ )
    {
        int v1, w1, s;
        cin >> v1 >> w1 >> s;
        int t = 1;
        while (t <= s)
        {
            cnt ++;
            v[cnt] = t * v1;
            w[cnt] = t * w1;
            s -= t;
            t *= 2;
        }
        if (s)
        {
            cnt ++;
            v[cnt] = s * v1;
            w[cnt] = s * w1;
        }
    }
    n = cnt;
    for (int i = 1; i <= n; i ++ )
        for (int j = m; j >= v[i]; j -- )
            f[j] = max(f[j], f[j - v[i]] + w[i]);
    cout << f[m] << endl;
    return 0;
}

多重背包问题 III

题目要求

题目描述:

image.png

输入格式:

image.png

输出格式:

输出一个整数,表示最大价值。

数据范围:

image.png

输入样例:

4 5
1 2 3
2 4 1
3 4 3
4 5 2

输出样例:

10

思路分析

本题用到了单调队列(滑动窗口进行优化),对该知识点不了解或不熟悉的同学请先读博客:单调队列,附上一张y总讲课截图辅助理解:

3.png

image.png

代码

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1010, M = 20010;
int v[N], w[N], s[N];
int f[N][M];
int q[M];
int main()
{
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i ++ ) cin >> v[i] >> w[i] >> s[i];
    for (int i = 1; i <= n; i ++ ) 
    {
        for (int r = 0; r < v[i]; r ++ )
        {
            int hh = 0, tt = -1;
            for (int j = r; j <= m; j += v[i] )
            {
                while (hh <= tt && j - q[hh] > s[i] * v[i]) hh ++;
                while (hh <= tt && f[i - 1][q[tt]] + (j - q[tt]) / v[i] * w[i] <= f[i - 1][j]) tt --;
                q[ ++ tt] = j;
                f[i][j] = f[i - 1][q[hh]] + (j - q[hh]) / v[i] * w[i];
            }
        }
    }
    cout << f[n][m] << endl;
    return 0;
}

代码优化

多重背包问题 I 一样的优化方式,我们发现在计算f[i][j]的时候只使用了f[i1][j]但是不可以使用 01背包的优化方法,因为我们使用的是 滑动窗口,这致使我们只能正向枚举体积。

滚动数组

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 20010;
int f[2][N];
int q[N];
int main()
{
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i ++ ) 
    {
        int v, w, s;
        cin >> v >> w >> s;
        for (int r = 0; r < v; r ++ )
        {
            int hh = 0, tt = -1;
            for (int j = r; j <= m; j += v)
            {
                while (hh <= tt && j - q[hh] > s * v) hh ++;
                while (hh <= tt && f[(i - 1) & 1][q[tt]] + (j - q[tt]) / v * w <= f[(i - 1) & 1][j]) tt --;
                q[ ++ tt] = j;
                f[i & 1][j] = f[(i - 1) & 1][q[hh]] + (j - q[hh]) / v * w;
            }
        }
    }
    cout << f[n & 1][m] << endl;
    return 0;
}

拷贝数组

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 20010;
int f[N], g[N];
int q[N];
int main()
{
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i ++ )
    {
        memcpy(g, f, sizeof f);
        int v, w, s;
        cin >> v >> w >> s;
        for (int r = 0; r < v; r ++ )
        {
            int hh = 0, tt = -1;
            for (int j = r; j <= m; j += v)
            {
                while (hh <= tt && j - q[hh] > v * s) hh ++;
                while (hh <= tt && g[q[tt]] + (j - q[tt]) / v * w <= g[j]) tt --;
                q[ ++ tt] = j;
                f[j] = g[q[hh]] + (j - q[hh]) / v * w;
            }
        }
    }
    cout << f[m] << endl;
    return 0;
}


目录
相关文章
|
算法 Android开发 索引
LeetCode 周赛上分之旅 #44 同余前缀和问题与经典倍增 LCA 算法
学习数据结构与算法的关键在于掌握问题背后的算法思维框架,你的思考越抽象,它能覆盖的问题域就越广,理解难度也更复杂。在这个专栏里,小彭与你分享每场 LeetCode 周赛的解题报告,一起体会上分之旅。
82 0
|
存储 人工智能 算法
【算法分析与设计】动态规划(下)(一)
【算法分析与设计】动态规划(下)
|
5月前
|
存储
【洛谷 P1255】数楼梯 题解(递归+记忆化搜索+高精度)
这是一个使用动态规划解决的“数楼梯”问题。给定楼梯数`N`,求不同上楼方式的数量。程序通过递归函数`f()`计算,其中`f(x) = f(x - 1) + f(x - 2)`,初始条件`f(1) = 1`,`f(2) = 2`。考虑到数据规模可能很大,使用了高精度加法运算。样例输入`4`,输出`5`。代码中定义了一个存储中间结果的向量`mem`,并提供了一个用于显示高精度数的`printv()`函数。
97 0
|
6月前
|
测试技术
【一刷《剑指Offer》】面试题 9:斐波那契数列(扩展:青蛙跳台阶、矩阵覆盖)
【一刷《剑指Offer》】面试题 9:斐波那契数列(扩展:青蛙跳台阶、矩阵覆盖)
|
算法 Java 测试技术
LeetCode 周赛上分之旅 #46 经典二分答案与质因数分解
学习数据结构与算法的关键在于掌握问题背后的算法思维框架,你的思考越抽象,它能覆盖的问题域就越广,理解难度也更复杂。在这个专栏里,小彭与你分享每场 LeetCode 周赛的解题报告,一起体会上分之旅。
66 0
LeetCode 周赛上分之旅 #46 经典二分答案与质因数分解
|
算法 C++
剑指offer(C++)-JZ71:跳台阶扩展问题(算法-动态规划)
剑指offer(C++)-JZ71:跳台阶扩展问题(算法-动态规划)
|
存储 算法
【算法分析与设计】动态规划(下)(三)
【算法分析与设计】动态规划(下)
|
消息中间件 人工智能 算法
【算法分析与设计】动态规划(下)(二)
【算法分析与设计】动态规划(下)
|
算法 C++
【每日算法Day 109】五大解法,带你深入了解完全背包方案数
【每日算法Day 109】五大解法,带你深入了解完全背包方案数
107 0
|
算法 C++