您的位置:首页 > 其它

背包问题模板

2017-09-03 19:42 239 查看

01背包

特点:每种物品只有一件

子问题定义状态

bag[i][v] : 前i件物品放到一个容量为v的背包中可以获得最大价值

转移状态方程

bag[i][v] = max(bag[i-1][v],bag[i-1][v-weight[i]] + value[i])


模板:

#include<iostream>
#include<string.h>
using namespace std;
int main(){
int n = 3;//n件物品
int v = 5;//背包的容量
int weight[n+1] = {0,3,2,2};//第n件物品的重量
int value[n+1] = {0,5,10,20};//第n件物品的价值
//结果最大价值为30
int bag[n+1][v+1];
memset(bag,0,sizeof(bag));//数组初始化,必须包含头文件<string.h>
for(int i = 1; i <= n; i++){//枚举物品
for(int j = 0; j <= v; j++){//枚举背包容量
if(j >= weight[i]){
bag[i][j] = max(bag[i-1][j],bag[i-1][j-weight[i]]+value[i]);
}else{
bag[i][j] = bag[i-1][j];
}
}
}
cout<<bag
[v]<<endl;
return 0;
}


效率分析

以上算法的时间复杂度为
O(N*V)
,空间复杂度也为
O(N*V)
.其中,N 表示物品个数,V 表示背包容量这里,时间复杂度不可以在优化了,但是空间复杂度可以继续优化到O(V).

空间复杂度优化

关键:由二维数组bag
[v]改为用一维数组bag[v]来保存中间变量。

关键代码修改:

int bag[v+1];
memset(bag,0,sizeof(bag));
for (int i = 1;i <= n;i++){//枚举物品
for (int j = v;j >= weight[i];j--){//枚举背包容量,防越界,j下限为 weight[i]
bag[j] = max(bag[j],bag[j-weight[i]]+value[i]);
}
}
cout<<bag[v]<<endl;


完全背包

每种物品的数量为无限

转移状态方程修改为:

bag[j] = max(bag[j],bag[j-k*weight[i]]+k*value[i]);


k:枚举能拿几件

完全背包主要加了一层循环来枚举可以拿走的物品数量count

count = v/weight[i];


原因:原因:假如有背包容量为6,有一物品重量为1,价值为2。此时根据背包的重量,最多只能拿6件而已。

模板:

#include<iostream>
#include<string.h>
using namespace std;
int main(){
int n = 3;//n件物品
int v = 5;//背包的容量
int weight[n+1] = {0,3,2,2};//第n件物品的重量
int value[n+1] = {0,5,10,20};//第n件物品的价值
//结果最大价值为40
int bag[v+1];
int count;
memset(bag,0,sizeof(bag));//数组初始化,必须包含头文件<string.h>
for(int i = 1; i <= n; i++){//枚举物品
for(int j = v; j >= weight[i]; j--){//枚举背包容量
count = j/weight[i];//在不超过当前背包容量的情况下,当前物品最多可以拿几件
for(int k = 0; k <= count; k++){
bag[j] = max(bag[j],bag[j-k*weight[i]]+k*value[i]);
}
}
}
cout<<bag[v]<<endl;
return 0;
}


多重背包

特点:每种物品的数量有上限

转移状态方程与完全背包相同:

bag[j] = max(bag[j],bag[j-k*weight[i]]+k*value[i]);


主要就是枚举数量count的取值变为

count = min(num[i],v/weight[i]);


原因:假如有背包容量为6,有一物品重量为1,价值为2,数量为10。虽然该物品有10件,但你的背包容量最多只允许你拿6件而已。

模板:

#include<iostream>
#include<string.h>
using namespace std;
int main(){
int n = 3;//n件物品
int v = 8;//背包的容量
int weight[n+1] = {0,1,2,2};//第n件物品的重量
int value[n+1] = {0,6,10,20};//第n件物品的价值
int num[n+1] = {0,10,5,2};//第n件物品的上限数量
//结果最大价值为64
int bag[v+1];
int count;
memset(bag,0,sizeof(bag));//数组初始化,必须包含头文件<string.h>
for(int i = 1; i <= n; i++){//枚举物品
for(int j = v; j >= weight[i]; j--){//枚举背包容量
count = min(num[i],j/weight[i]);//在不超过当前背包容量的情况下,当前物品最多可以拿几件
for(int k = 0; k <= count; k++){
bag[j] = max(bag[j],bag[j-k*weight[i]]+k*value[i]);
}
}
}
return 0;
}


关于背包问题的参考资料:

背包问题九讲笔记_01背包

背包问题九讲笔记_完全背包

背包问题九讲笔记_多重背包
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: