多重背包问题(一)

简介: AcWing算法提高课内容,本文讲解 动态规划

前言

AcWing算法提高课内容,本文讲解 动态规划

本篇包括以下题目:

⭐️ 多重背包问题 I

⭐️ 多重背包问题 II

⭐️ 多重背包问题 III

⭐️ AcWing 1019. 庆功会

写博客有哪里不完善的地方或者有哪里表达错误希望大家提出来,博主会立即改正!望大家海涵



多重背包问题 I

题目要求

题目描述:

image.png

输入格式:

image.png

输出格式:

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

数据范围:

image.png

输入样例:

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

输出样例:

10

思路分析

数据范围很小,暴力枚举即可,不需要过多操作,f[i][j]代表的是只从前 i 件物品中选,且总体积不超过 j的价值最大值。

代码

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 110;
int f[N][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 j = 0; j <= m; j ++ )
            for (int k = 0; k <= s && k * v <= j; k ++ )
                f[i][j] = max(f[i][j], f[i - 1][j - k * v] + k * w);
    }
    cout << f[n][m] << endl;
    return 0;
}

代码优化

image.png

滚动数组


#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 110;
int f[2][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 j = 0; j <= m; j ++ )
            for (int k = 0; k <= s && k * v <= j; k ++ )
                f[i & 1][j] = max(f[i & 1][j], f[(i - 1) & 1][j - k * v] + k * w);
    }
    cout << f[n & 1][m] << endl;
    return 0;
}

拷贝数组

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

逆循环优化

逆循环的优化方式和 01 背包的优化是相同的,原理也是一致的,对于体积逆序枚举即可实现,这样的优化方法可真正实现仅用一维数组表示二维变量:

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 110;
int f[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 j = m; ~j; j -- )
            for (int k = 0; k <= s && k * v <= j; k ++ )
                f[j] = max(f[j], f[j - k * v] + k * w);
    }
    cout << f[m] << endl;
    return 0;
}

多重背包问题 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;
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;
}


#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循环体积)




目录
相关文章
|
6月前
多重背包问题
多重背包问题
58 0
|
1月前
|
算法
浅谈完全背包问题
浅谈完全背包问题
|
6月前
多重背包和分组背包
多重背包和分组背包
|
6月前
完全背包问题
完全背包问题
55 0
动态规划之01背包问题和完全背包问题
动态规划之01背包问题和完全背包问题
|
算法 C语言 C++
【动态规划】多重背包问题,分组背包问题
与完全背包问题不同的是,每种东西都是有限件,前两种状态就不再过多赘述
147 4
|
算法 C语言 C++
【动态规划】背包问题(01背包,完全背包)
有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。
124 0
动态规划——多重背包、分组背包
动态规划——多重背包、分组背包
62 0
动态规划:多重背包问题
动态规划:多重背包问题
70 0
|
算法 决策智能
背包问题——01背包|完全背包 1
背包问题——01背包|完全背包
312 0