0 1背包问题
01背包(ZeroOnePack):有N件物品和一个容量为V的背包。(每种物品均只有一件)第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。
题目
有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。
基本思路
这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。
用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。则其状态转移方程便是:
f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}
初始化: f0
For(i=1 to n)
{
for( j=1 to v )
{
f[i][j]=f[i-1][j];
if(j>=c[i])
{
f[i][j]=max{f[i-1][j] ,f[i-1][j-c[i]]+w[i]};
}
}
}
第一种是第i件不放进去,这时所得价值为:f[i-1][v]
第二种是第i件放进去,这时所得价值为:f[i-1][v-c[i]]+w[i]
最后比较第一种与第二种所得价值的大小,哪种相对大,f[i][v]的值就是哪种。
背包容
量
|
0
|
1
|
2
|
3
|
4
|
5
|
6
|
7
|
8
|
9
|
1
0
|
1
1
|
1
2
|
1
3
|
1
4
|
1
5
|
5
物品
|
0
|
0
|
0
|
0
|
0
|
0
|
6
|
12
|
12
|
15
|
15
|
18
|
22
|
22
|
25
|
25
|
4
物品
|
0
|
0
|
3
|
3
|
3
|
3
|
3
|
12
|
12
|
15
|
15
|
18
|
22
|
22
|
25
|
25
|
3
物品
|
0
|
0
|
0
|
0
|
0
|
0
|
0
|
12
|
12
|
15
|
15
|
15
|
22
|
22
|
22
|
22
|
2
物品
|
0
|
0
|
0
|
0
|
3
|
12
|
12
|
12
|
12
|
15
|
15
|
15
|
15
|
15
|
15
|
15
|
1
物品
|
0
|
0
|
0
|
0
|
0
|
12
|
12
|
12
|
12
|
12
|
12
|
12
|
12
|
12
|
12
|
12
|
例子:5个物品,(重量,价值)分别为:(5,12),(4,3),(7,10),(2,3),(6,6)
背包的容量为15
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int main()
{
int f[6][16];
int cos[6]={0,5,4,7,2,6};
int val[6]={0,12,3,10,3,6};
memset(f,0,sizeof(f));
for(int i=1;i<=5;i++)
{
for(int j=1;j<=15;j++)
{
f[i][j]=f[i-1][j];
if(j>=cos[i])
{
f[i][j]=max(f[i-1][j],f[i-1][j-cos[i]]+val[i]);
}
}
}
for(int i=1;i<=5;i++)
{
for(int j=1;j<=15;j++)
printf("%d ",f[i][j]);
printf("\n");
}
printf("最大价值:%d\n",f[5][15]);
}
这里是用二位数组存储的,可以把空间优化,用一位数组存储!
代码:
优化:将f数组转化为一维数组
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int main()
{
int f[16];
int cos[6]={0,5,4,7,2,6};
int val[6]={0,12,3,10,3,6};
memset(f,0,sizeof(f));
for(int i=1;i<=5;i++)
{
for(int j=15;j>=1;j--)
{
if(j>=cos[i])
{
f[j]=max(f[j],f[j-cos[i]]+val[i]);
}
}
}
for(int i=1;i<=15;i++)
{
printf("%d ",f[i]);
}
}