完全背包简介
题目描述:
给出N个物品(一个物品可以选择多次,没有限制),背包最大承重为M,每个物品有一个重量w,一个价值v。如何选择才能在重量不超过M的情况下,使选择的物品的价值总和最大。
输入格式:
第一行:是两个正整数N,M。
第2 ~ (n + 1)行:每行两个正整数w和v。
输出格式:
一个整数,为最大价值总和是多少。
输入样例:
6 12
4 8
6 10
2 6
2 3
5 7
1 2
输出样例:
36
解决方法
完全背包与零一背包非常相似。只不过零一背包中一个物品,要么选一次要么不选。而完全背包选择的次数是没有限制的。
注:如果你还没学过零一背包,可以去此网址先学习一下https://blog.csdn.net/SkeletonKing233/article/details/94893608
那么这该怎么办呢?还记得零一背包那篇文章中,在一维数组解法模块中我写到过的后效性吗?零一背包中我们为了避免多选而采取从m到w[i]倒着循环这种方式,使其无后效性。而现在恰恰相反,我们需要这种后效性,所以我们从我w[i]到m正着循环就ok了。
代码如下,只不过是把一维数组解零一背包那个代码中第二重循环翻过来便是了。
(PS:NR是指物品个数的上限,MR是指重量的上限)
# include <cstdio>
# include <iostream>
# include <cmath>
# include <cstring>
# include <algorithm>
using namespace std;
# define FOR(i, a, b) for(int i = a; i <= b; i++)
# define _FOR(i, a, b) for(int i = a; i >= b; i--)
const int NR = 100000, MR = 100000000;
int n, m;
int w[NR + 10], v[NR + 10];
int dp[MR + 10];
int main()
{
scanf("%d%d", &n, &m);
FOR(i, 1, n)
scanf("%d%d", &w[i], &v[i]);
FOR(i, 1, n)
FOR(j, w[i], m)
dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
printf("%d\n", dp[m]);
return 0;
}
God Bless You For Ever!