一、背包九讲总述
关于动态规划问题,最典型的就是背包九讲,先理解背包九讲后再总结关于动态规划的问题。
1、01背包问题
2、完全背包问题
3、多重背包问题
4、混合背包问题
5、二维费用的背包问题
6、分组背包问题
7、背包问题求方案数
8、求背包问题的方案
9、有依赖的背包问题
上两篇讲述了c++背包九讲之01背包和c++背包九讲之完全背包
二、多重背包问题
多重背包问题: 有n件物品和一个容量为C的背包, 每种物品有k[i]件,第i件物品的费用是w[i],价值是v[i]。求解将哪些物品装入背包可使价值总和最大。
这个就不用多叙述了,相信看了上两篇文章的小伙伴非常容易理解这个问题。区别无非就是数量的限制。下面从几个角度来实现一下:
示例:参考这个图多重背包问题
其中,V表示价值,W表示重量,K表示数量
方法一:添加附加数量限制条件
#include<iostream>
#include<algorithm>
using namespace std;
//全局变量定义在堆区,自动初始化
int V[100][100];
int x[100];
int k[100];
int packet(int n, int C, int v[], int w[],int k[])
{
int i = 0, j = 0,l = 0;
//此循环为核心,重点!!
for (i = 0; i <= n; i++)
{
for (j = 1; j <= C; j++)
{
//注意约束条件,不能无限的加
for (l = 1; l <= k[i] && l*w[i] <= j; l++)
{
if (j < w[i])
{
V[i][j] = V[i - 1][j];
}
else
V[i][j] = max(V[i - 1][j], V[i - 1][j - l*w[i]] + l*v[i]);
}
}
}
cout << V[n][C] << endl;
return 0;
}
int main()
{
int n; //输入的物品个数
int C; //最大的容量
int v[100] = { 0 }; //第i个物品的价值
int w[100] = { 0 }; //第i个物品的重量
int k[100] = { 0 };
cout << "输入物品个数" << endl;
cin >> n;
cout << "输入背包容量" << endl;
cin >> C;
cout << "输入各个物品的价值" << endl;
for (int i = 1; i <= n; i++)
{
cin >> v[i];
}
cout << "输入各个物品的重量" << endl;
for (int i = 1; i <= n; i++)
{
cin >> w[i];
}
cout << "输入各个物品的数量" << endl;
for (int i = 1; i <= n; i++)
{
cin >> k[i];
}
packet(n, C, v, w, k);
while (1);
}
方法二:转化为01问题(二维数组)
#include<iostream>
#include<algorithm>
using namespace std;
//全局变量定义在堆区,自动初始化
int V[100][100];
int x[100];
int k[100];
int packet(int n, int C, int v[], int w[], int k[])
{
int i = 0, j = 0;
int l = n;
//扩大物体数量
for (i = 0; i <= n; i++)
{
if (k[i] != 1)
{
w[l+1] = w[i];
v[l+1] = v[i];
l++;
k[i]--;
}
}
//此循环为核心,重点!!
for (i = 0; i <= l; i++)
{
for (j = 1; j <= C; j++)
{
if (j < w[i])
{
V[i][j] = V[i - 1][j];
}
else
V[i][j] = max(V[i - 1][j], V[i - 1][j - w[i]] + v[i]);
}
}
cout << V[l][C] << endl;
cout << endl;
return 0;
}
int main()
{
int n; //输入的物品个数
int C; //最大的容量
int v[100] = { 0 }; //第i个物品的价值
int w[100] = { 0 }; //第i个物品的重量
int k[100] = { 0 };
cout << "输入物品个数" << endl;
cin >> n;
cout << "输入背包容量" << endl;
cin >> C;
cout << "输入各个物品的价值" << endl;
for (int i = 1; i <= n; i++)
{
cin >> v[i];
}
cout << "输入各个物品的重量" << endl;
for (int i = 1; i <= n; i++)
{
cin >> w[i];
}
packet(n, C, v, w, k);
while (1);
}
方法三:转化为01问题(滚动一维数组)
#include<iostream>
#include<algorithm>
using namespace std;
//全局变量定义在堆区,自动初始化
int x[100];
int k[100];
int V[100];
int packet(int n, int C, int v[], int w[], int k[])
{
int i = 0, j = 0;
int l = n;
for (i = 0; i <= n; i++)
{
if (k[i] != 1)
{
w[l+1] = w[i];
v[l+1] = v[i];
l++;
k[i]--;
}
}
//此循环为核心,重点!!
for (i = 0; i <= l; i++)
{
//滚动数组优化空间,逆序
for (j = C; j > 0; j--)
{
if (j < w[i])
{
V[j] = V[j];
}
else
V[j] = max(V[j], V[j - w[i]] + v[i]);
}
}
cout << V[C] << endl;
cout << endl;
return 0;
}
int main()
{
int n; //输入的物品个数
int C; //最大的容量
int v[100] = { 0 }; //第i个物品的价值
int w[100] = { 0 }; //第i个物品的重量
int k[100] = { 0 };
cout << "输入物品个数" << endl;
cin >> n;
cout << "输入背包容量" << endl;
cin >> C;
cout << "输入各个物品的价值" << endl;
for (int i = 1; i <= n; i++)
{
cin >> v[i];
}
cout << "输入各个物品的重量" << endl;
for (int i = 1; i <= n; i++)
{
cin >> w[i];
}
cout << "输入各个物品的数量" << endl;
for (int i = 1; i <= n; i++)
{
cin >> k[i];
}
packet(n, C, v, w, k);
while (1);
}