文章目录
01背包
背包问题
- 01背包:对于物品(只有1个),选择或不选择
- 完全背包:对于物品(无穷多个),选择几个
模板
(1)总模板
const int N=10000; //最多物品个数
const int M=100; //最大容量
int w[N], c[N]; //每个物品的容量,价值
int dp[M]; // dp[i]:容量恰好为i的装入物品价值和
/*
容量dp[]下标:0到 m-1
物品w[],c[]下标:1到 n
*/
bool choose[M][N]; //choose[i][j]:容量为i时,是否选择了j物品
for(i=0; i<m; i++){
dp[i] = 0;
}
for(int i=1; i<=n; i++){
for(int j=m; j>=w[i]; j--){ //逆序
dp[j] = max(dp[j], dp[j-w[i]]+c[i]); //当物品只有容量,没有价值时,
//dp[j] = max(dp[j], dp[j-w[i]]+w[i]);
}
}
(2) 恰好装入容量=m,求dp[m]
sort(w+1, w+n+1, greater<int>()); // 从大到小
// 求dp[m]
fill(choose[0], choose[0]+M*N, false);
for(int i=0; i<m; i++){
dp[i] = 0;
}
for(int i=1; i<=n; i++){
for(int j=m; j>=w[i]; j--){
if(dp[j] <= dp[j-w[i]]+w[i]){ //相等时,选择后者
choose[j][i] = true;
dp[j] = dp[j-w[i]]+w[i];
}
}
}
//
if(dp[m]!=m){
printf("No Solution");
}else{
// 寻找物品,逆序
vector<int> vect;
int i=n,j=m;
while(j>0){
if(choose[j][i]==true){
vect.push_back(w[i]);
j -= w[i];
}
i--;
}
for(int i=0; i<vect.size(); i++){
if(i!=0){
printf(" ");
}
printf("%d", vect[i]);
}
}
多个答案时
- 求物品的价值:最小序列
sort(w[]):从大到小 - 求物品的价值:最大序列
sort(w[]):从小到大
(3)装入不超过m,求dp[]中的最大值
1068(30:01背包)
(1)题目
01背包
(2)代码
#include<cstdio>
#include<algorithm>
#include<vector>
#include<functional>
using namespace std;
const int N = 10000+100;
const int M=100+100;
int w[N];
int dp[M];
bool choose[M][N];
int main(){
//freopen("in.txt", "r",stdin);
int n,m;
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++){
scanf("%d", &w[i]);
}
sort(w+1, w+n+1, greater<int>());
// 求dp[m]
fill(choose[0], choose[0]+M*N, false);
for(int i=0; i<m; i++){
dp[i] = 0;
}
for(int i=1; i<=n; i++){
for(int j=m; j>=w[i]; j--){
if(dp[j] <= dp[j-w[i]]+w[i]){
choose[j][i] = true;
dp[j] = dp[j-w[i]]+w[i];
}
}
}
if(dp[m]!=m){
printf("No Solution");
}else{
// 寻找物品,逆序
vector<int> vect;
int i=n,j=m;
while(j>0){
if(choose[j][i]==true){
vect.push_back(w[i]);
j -= w[i];
}
i--;
}
for(int i=0; i<vect.size(); i++){
if(i!=0){
printf(" ");
}
printf("%d", vect[i]);
}
}
//fclose(stdin);
return 0;
}