一、背包问题是什么?
背包问题是将多个不同质量,不同体积的物体放入一个容积一定背包中,求这个背包最多可以装多重的东西
二、类别
1.01背包
一个物体只有一个,每个物体只有0(不放入)和1(放入)两种状态
例题
Question
Many years ago , in Teddy’s hometown there was a man who was called “Bone Collector”. This man like to collect varies of bones , such as dog’s , cow’s , also he went to the grave …
The bone collector had a big bag with a volume of V ,and along his trip of collecting there are a lot of bones , obviously , different bone has different value and different volume, now given the each bone’s value along his trip , can you calculate out the maximum of the total value the bone collector can get ?
Input
The first line contain a integer T , the number of cases.
Followed by T cases , each case three lines , the first line contain two integer N , V, (N <= 1000 , V <= 1000 )representing the number of bones and the volume of his bag. And the second line contain N integers representing the value of each bone. The third line contain N integers representing the volume of each bone.
Output
One integer per line representing the maximum of the total value (this number will be less than 231).
Sample Input
1
5 10
1 2 3 4 5
5 4 3 2 1
Sample Output
14
代码
#include<bits/stdc++.h>
#define RE0 return 0;
using namespace std;
int dp[1005];
typedef struct BONE
{
int val, vol;
bool friend operator <(BONE a, BONE b)
{
return a.vol < b.vol;
}
} bone;
bone a[1006];
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
memset(dp, 0, sizeof dp);
int N, V;
scanf("%d%d", &N, &V);
for (int i = 0; i < N; ++i)
{
scanf("%d", &a[i].val);
}
for (int i = 0; i < N; ++i)
{
scanf("%d", &a[i].vol);
}
sort(a, a + N);
for (int i = 0; i < N; ++i)
{
for (int j = V; j >= 0; --j)
{
if (j >= a[i].vol)
{
dp[j] = max(dp[j], dp[j - a[i].vol] + a[i].val);
}
}
}
printf("%d\n", dp[V]);
}
RE0
}
2.完全背包
放入背包时,一种物体可以取无数次的情况
例题
Question
不死族的巫妖王发工资拉,死亡骑士拿到一张N元的钞票(记住,只有一张钞票),为了防止自己在战斗中频繁的死掉,他决定给自己买一些道具,于是他来到了地精商店前.
死亡骑士:“我要买道具!”
地精商人:“我们这里有三种道具,血瓶150块一个,魔法药200块一个,无敌药水350块一个.”
死亡骑士:“好的,给我一个血瓶.”
说完他掏出那张N元的大钞递给地精商人.
地精商人:“我忘了提醒你了,我们这里没有找客人钱的习惯的,多的钱我们都当小费收了的,嘿嘿.”
死亡骑士:"…"
死亡骑士想,与其把钱当小费送个他还不如自己多买一点道具,反正以后都要买的,早点买了放在家里也好,但是要尽量少让他赚小费.
现在死亡骑士希望你能帮他计算一下,最少他要给地精商人多少小费.
Input
输入数据的第一行是一个整数T(1<=T<=100),代表测试数据的数量.然后是T行测试数据,每个测试数据只包含一个正整数N(1<=N<=10000),N代表死亡骑士手中钞票的面值.
注意:地精商店只有题中描述的三种道具.
Output
对于每组测试数据,请你输出死亡骑士最少要浪费多少钱给地精商人作为小费.
Sample Input
2
900
250
Sample Output
0
50
代码
#include<bits/stdc++.h>
#define RE0 return 0;
const int maxn=100050;
const int inf = 0x3f3f3f3f;
using namespace std;
int dp[maxn], v[maxn] = { 0,150,200,350 }, w[maxn] = { 0,150,200,350 };
int main()
{
int T;
scanf("%d", &T);
for (int k = 0; k < T; ++k)
{
int m;
scanf("%d", &m);
memset(dp, 0, sizeof dp);
for (int i = 1; i < 4; ++i)
{
int flag = 0;
for (int j = m; j >= v[i]; --j)
{
int last = dp[j];
dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
if (last != dp[j])
{
flag = 1;
}
}
if (flag) // 如果这个被取过,就重新再来一次看能否再去
{
--i;
}
}
printf("%d\n", m - dp[m]);
}
RE0
}
3.多重背包
放入背包时,每种物体的数量不同
例题
Question
急!灾区的食物依然短缺!
为了挽救灾区同胞的生命,心系灾区同胞的你准备自己采购一些粮食支援灾区,现在假设你一共有资金n元,而市场有m种大米,每种大米都是袋装产品,其价格不等,并且只能整袋购买。
请问:你用有限的资金最多能采购多少公斤粮食呢?
Input
输入数据首先包含一个正整数C,表示有C组测试用例,每组测试用例的第一行是两个整数n和m(1<=n<=100, 1<=m<=100),分别表示经费的金额和大米的种类,然后是m行数据,每行包含3个数p,h和c(1<=p<=20,1<=h<=200,1<=c<=20),分别表示每袋的价格、每袋的重量以及对应种类大米的袋数。
Output
对于每组测试数据,请输出能够购买大米的最多重量,你可以假设经费买不光所有的大米,并且经费你可以不用完。每个实例的输出占一行。
Sample Input
1
8 2
2 100 4
4 100 2
Sample Output
400
代码
#include<bits/stdc++.h>
#define RE0 return 0;
const int maxn=100050;
const int inf = 0x3f3f3f3f;
using namespace std;
int dp[maxn], v[maxn], w[maxn], newv[maxn], neww[maxn], num[maxn];
int main()
{
int T;
scanf("%d", &T);
for (int k = 0; k < T; ++k)
{
int n, m;
int x = 1;
scanf("%d%d", &m, &n);
memset(dp, 0, sizeof dp);
for (int i = 1; i <= n; ++i)
{
scanf("%d%d%d", &v[i], &w[i], &num[i]);
for (int j = 1; j <= num[i]; j *= 2)
{
neww[x] = w[i] * j;
newv[x] = v[i] * j;
++x;
num[i] -= j;
}
if (num[i] > 0)
{
neww[x] = w[i] * num[i];
newv[x] = v[i] * num[i];
++x;
}
}
for (int i = 1; i < x; ++i)
{
for (int j = m; j >= newv[i]; --j)
{
dp[j] = max(dp[j], dp[j - newv[i]] + neww[i]);
}
}
printf("%d\n", dp[m]);
}
RE0
}