动归经典:三类背包问题

本文介绍了0-1背包、完全背包和多重背包的经典动态规划问题,通过实例和容斥原理阐述了解决策略,以及代码实现。
摘要由CSDN通过智能技术生成

目录

(1)0-1背包

题目描述

输入

输出

样例输入1

样例输出1

数据规模与约定

题解:

(2)完全背包

题目描述

输入

输出

样例输入

样例输出

数据规模与约定

题解:

(3)多重背包

题目描述

输入

输出

样例输入1

样例输出1

数据规模与约定

题解:


(1)0-1背包

题目描述

给一个能承重V的背包,和n件物品,我们用重量和价值的二元组来表示一个物品,第i件物品表示为(Vi,Wi),问:在背包不超重的情况下,得到物品的最大价值是多少?

54E9C51263E1462585A8F6595841EEC0.jpg


输入

第一行输入两个数 V,n,分别代表背包的最大承重和物品数。

接下来n行,每行两个数Vi,Wi,分别代表第i件物品的重量和价值。

(Vi≤V≤10000,n≤100,Wi≤1000000)

输出

输出一个整数,代表在背包不超重情况下所装物品的最大价值。


样例输入1
15 4
4 10
3 7
12 12
9 8
样例输出1
19

数据规模与约定

时间限制:1 s

内存限制:64 M

100% 的数据保证(Vi≤V≤10000,n≤100,Wi≤1000000)

题解:

这道题我们选取的状态为:dp[i][j]代表前i件物品,选取的总体积最大为j时能获得的最大价值。然后我们可以利用容斥原理的思想去思考递推式:将状态整个分成两部分——选取了第i件物品的和没选取第i件物品的。其中没选取第i件物品的最大价值可以被表示为dp[i-1][j],至于选取了第i件物品的,我们可以按以下思路来想:我们先给第i件物品留好一个位置,这样再将所有结果列出即可,也就是:dp[i-1][j-v[i]]+w[i]。上面那个表达式解释一下就是:为第i个留好位置(也就是[j-v[i]]),再去计算没有i物品的且为物品i留有位置的所有的情况(也就是dp[i-1][j-v[i]]),最后再把第i个物品的的价值加上去即可。

值得一提的点是,这道题不需要我们特别地去设定初值。

代码:

#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;

int dp[105][10005] = { 0 };//前i件物品,选取的总体积最大为j时能获得的最大价值
int w[105], v[105];

int main()
{
    int V, N;
    cin >> V >> N;
    for (int i = 1;i <= N;i++)
    {
        cin >> v[i] >> w[i];
    }
    for (int i = 1;i <= N;i++)
    {
        for (int j = 1;j <= V;j++)
        {
            if (j >= v[i])//背包剩下的空间能放下第i件物品
                dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - v[i]] + w[i]);
            else dp[i][j] = dp[i - 1][j];
        }
    }
    cout << dp[N][V];

    return 0;
}

(2)完全背包

题目描述

有N种物品和一个容量为 V 的背包,每种物品都有无限件可用。

第 i 种物品的体积是Ci,价值是Wi。求解在不超过背包容量的情况下,能够获得的最大价值。

54E9C51263E1462585A8F6595841EEC0.jpg


输入

第一行为两个整数N、V(1≤N,V≤10000),分别代表题目描述中的物品种类数量N和背包容量V。

后跟N行,第 i 行两个整数Ci、Vi,分别代表每种物品的体积和价值。

输出

输出一个整数,代表可获得的最大价值。


样例输入
5 20
2 3
3 4
10 9
5 2
11 11
样例输出
30

数据规模与约定

时间限制:1s

内存限制:64M

对于100%的数据,1≤N,V≤10000。

题解:

本题与上题几乎一样,除了一点:上一题中每一件物品只有一个,而这一题中每一件物品都有无限个,这其实并不会带来多大的不同,我们还是用上提的思路去思考:选取状态为:dp[i][j]代表前i件物品,选取的总体积最大为j时能获得的最大价值。然后利用容斥原理的思想:将状态整个分成两部分——选取了第i件物品的和没选取第i件物品的。没选的依然是dp[i-1][j],但是选了的不一样。由于这道题每件物品都有无限个,因此我们的表达式应该是:dp[i][j-v[i]]+w[i]。依然是为至少一个物品i留出空位,但若是沿袭上题的表达式,就会变成只选择一个物品i。

代码:

#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;

int dp[2][10005] = { 0 };//前i件物品,选取的总体积最大为j时能获得的最大价值
int w[10005], v[10005];

int main()
{
    int V, N;
    cin >> N >> V;
    for (int i = 1;i <= N;i++)
    {
        cin >> v[i] >> w[i];
    }
    for (int i = 1;i <= N;i++)
    {
        for (int j = 1;j <= V;j++)
        {
            if (j >= v[i])//背包的空间能放下第i件物品
                dp[i % 2][j] = max(dp[(i - 1) % 2][j], dp[i % 2][j - v[i]] + w[i]);
            else dp[i % 2][j] = dp[(i - 1) % 2][j];
        }
    }
    cout << dp[N % 2][V];

    return 0;
}

(3)多重背包

题目描述

给有一个能承重 V 的背包,和n种物品,每种物品的数量有限多,我们用重量、价值和数量的三元组来表示一个物品,第 i 件物品表示为(Vi,Wi,Si),问在背包不超重的情况下,得到物品的最大价值是多少?

54E9C51263E1462585A8F6595841EEC0.jpg


输入

第一行输入两个数V、n,分别代表背包的最大承重和物品种类数。

接下来 n 行,每行三个数 Vi、Wi、Si,分别代表第 i 种物品的重量、价值和数量。

输出

输出一个整数,代表在背包不超重情况下所装物品的最大价值。


样例输入1
15 4
4 10 5
3 7 4
12 12 2
9 8 7
样例输出1
37

数据规模与约定

时间限制:1 s

内存限制:64 M

60% 的数据保证(Vi≤V≤1000,n≤100,Si≤10,Wi≤1000)​

100% 的数据保证(Vi≤V≤100000,n≤100,Si≤100000,Wi≤1000)

题解:

在我们看完上述两道题之后,会发现这道题,其实可以把它当成是一个01背包的问题:想想看,把每一个物品都当成是一个独立的物品,也就是说,有多个价值和体积都相同的物品。有点像是脑筋急转弯。当然这不是这道题最正确的解法。有关于正确的解法,放在之后的文章中详细说明。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值