好久没有更新博客了,这几天一直在学习WEB开发基础,忽略了算法的知识了,
今天我想讲一下01背包 完全背包 多重背包的知识,虽然网上一查一大把,我看了一下都认为不错
01背包是选择货物(也有其他类型,在这里我就用“货物”来代指了)重要的方法。。(指针对于每种货物只有一种)
01顾名思义,一种货物(也有可能被转化成其他,根据题意辨别)要么是0(就是不拿)要么是1(就是拿)。。
首先我们看一下背包的的本质:max1[j] = MAX(max1[j],max1[j-b[i].v]+b[i].w)意思就是你付出的代价得到的回报和你不付出代价的回报哪个更大就选择哪个(MAX是个函数表示在两个选项中选择一个最大的,max1[j]是你不付出代价的回报,max1[j-b[i].v]+b[i].w是你付出的代价
得到回报b[i]),,这里就会有同学可能问了不付出代价怎么可能有回报呢?
如果你有这个疑问你就是走入了一个误区,,,让咱们带着问题接着往
下看,,,,
我们先来做一个事例看一下:
代码如下
#include
#include
#include
#include
using namespace std;
const int MAX = 10020;
struct Knapsack
{
int v;
int w;
}b[MAX];
int value[MAX];
int n, m;
int Knapsack_01 ( )
{
int i, j;
for ( i = 0;i < n; i++ )
{
for ( j = m;j >= b[i].v;j-- )
{
value[j] = max(value[j], value[j-b[i].v]+b[i].w);
}
}
return value[m];
}
int main()
{
int i;
while ( ~scanf ( "%d %d", &n, &m ) )
{
for ( i = 0;i < n; i++ )
{
scanf ( "%d %d", &b[i].v, &b[i].w );
}
memset( value, 0, sizeof(value) );
int sum = Knapsack_01( );
printf ( "%d\n", sum );
}
return 0;
}
这里我们先做一个表格看一下这个代码跑的程序,,
有很多的刚接触01背包的并不能十分懂得01背包的作用,认为还不如直接贪心选择单位体积获得最大价值的方法依次放货物来的实在,,真的是这样吗??
下面我来编一组数来看看01背包和贪心的区别
输入
5 10
3 12
3 13
2 15
1 2
2 3
贪心会输出 42
01背包会输出 43
到底差在哪里呢?
哦原来贪心选了第四种物品,而01选了第五种物品啊!!自己想想为什么??
完全背包是指对于每种货物有若干种
而他的算法和01背包几乎可以说是别无而致,微微的一点区别时
将内循环的倒序改为正序
for (int i=0; i
为什么之改变了内循环就可以使所得的结果大不相同呢?
这是因为正序使背包的空间可以被完全利用,小伙伴们可以自己模拟一下看看
/*
完全背包
V=10,N=3,c[]={3,4,5}, w={4,5,6}
(1)背包不一定装满
计算顺序是:从左往右,自上而下: 每个物品可以放多次,前面的会影响后面的
(2)背包刚好装满
计算顺序是:从左往右,自上而下。注意初始值,其中-inf表示负无穷
*/
多重背包是指一件物品可以有有限种数量
就比如说这个题
#include
#include
#include
#include
using namespace std;
int value[105];
struct beibao
{
int c;
int v;
int b;
} a[105];
int main()
{
int i, j, k;
int t, m, n;
scanf ( "%d", &t );
while ( t-- )
{
scanf ( "%d %d", &n, &m );
for( i = 1; i <= m; i++ )
scanf ( "%d %d %d", &a[i].c, &a[i].v, &a[i].b );
memset(value, 0, sizeof(value) );
for( i = 1; i <= m; i++)
for( j = 1; j <= a[i].b; j++)
for( k = n; k >= a[i].c; k--)
value[k] = max(value[k], value[k-a[i].c]+a[i].v);
printf ( "%d\n", value[n] );
}
return 0;
}
大家可以参考一下。