完全背包问题的阐述:
题目描述
设有n种物品,每种物品有一个重量及一个价值。但每种物品的数量是无限的,同时有一个背包,最大载重量为M,今从n种物品中选取若干件(同一种物品可以多次选取),使其重量的和小于等于M,而价值的和为最大。
输入
第一行:两个整数,M(背包容量,M≤200)和N(物品数量,N≤30);
第2…N+1行:每行二个整数Wi,Ci,表示每个物品的重量和价值。
输出
仅一行,一个数,表示最大总价值。
样例输入
10 4
2 1
3 3
4 5
7 9
样例输出
max=12
完全背包问题跟01背包问题的区别在于:
01背包问题的物品只能选择一个,那么只存在选与不选的区别。
完全背包的同一物品可以选多个,但是重量不能超过背包的容量。
完全背包背包问题可分为两大类:
一.当前物品的重量超过背包容量(不选)
二.选择当前物品
{
选择0件
选择1件
…
选择k件
}
求选择物品件数的最大值为当前的结果
设f[i][j]为选择当前i个物品,最大容量为j的情况下,能装入的最大价值,选择的物品件数为k,第i件物品的价值和重量分别为v[i],w[i]。
选择k件物品后的价值f[i][j]为 f[i][j] = f[i-1][j-w[i]*k]+v[i]*k
状态转移方程如下图所示:
代码实现:
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXCAPACITH = 202; //背包最大容量
const int MAXNUM = 32; //最大物品数量
int w[MAXNUM]; //物品的重量
int v[MAXNUM]; //物品的价值
int f[MAXNUM][MAXCAPACITH]; //选择物品i,最大容量为j的情况下,最大能装入的物品价值
void complete_backpack(int M, int N)
{
for (int i = 1; i <= N; i++)
{
for (int j = 1; j <= M; j++)
{
if (w[i] > j)
{
f[i][j] = f[i - 1][j];
}
else
{
int max = f[i - 1][j];
for (int k = 0; (j - w[i] * k) >= 0; k++) //选择 k = 0, 1, 2, 3...中能产生最大价值的物品数量k
{
if (f[i - 1][j - w[i] * k] + v[i] * k > max)
{
max = f[i - 1][j - w[i] * k] + v[i] * k;
}
}
f[i][j] = max;
}
}
}
printf("max=%d\n", f[N][M]);
}
int main()
{
int M, N;
scanf("%d %d",&M, &N);
for (int i = 1; i <= N; i++)
{
scanf("%d %d", &w[i], &v[i]);
}
complete_backpack(M, N);
return 0;
}