01背包
01 背包问题
一般意义上的 01 背包
参考链接:
https://www.programmercarl.com/背包理论基础01背包-1.html#_01-背包
描述:
一般有 n 件物品,用最大容量为 j 的背包去装
每件物品重量为 w[i], 价值为 v[i]
求容量为 k 的背包所能装的物品的最大价值。
题目 1--csp 何以包邮?
本题中, 需要装若干本书,使得书的价格大于等于 x 且最小。
用 01 背包解释:
物品的价格和重量一样,
背包的容量大于等于 x,且要尽量小,与一般情况下相反
我们可以反过来思考: 找若干件物品,用最大容量为 sum-x 的背包来装,并且尽量装最多,那么剩下的那些物品不就是我们要的了吗?
代码实现:
#include<iostream>
#include<cstring>
using namespace std;
//动态规划
//先开数组,根据题目信息开大一点(注意数组较大时用全局变量存储在堆中,因为栈太小了)
// int price[40] = {0};//1~n
// int dp[40][300004] = {{0}};//i:0~n,j:0~sum-x,0行和0列为虚拟0行
int main(){
int n,x;
scanf("%d %d",&n,&x);
int price[n+5] ={0};
int sum = 0;
for(int i = 1;i<=n;i++){
scanf("%d",&price[i]);
sum += price[i];
}
int dp[n+5][sum-x+5];
memset(dp,0,sizeof(dp));
for(int i = 1;i<=n;i++){
for(int j = 0;j<=sum-x;j++){
if(j < price[i]){
dp[i][j] = dp[i-1][j];
} else{
dp[i][j] = max(dp[i-1][j], dp[i-1][j-price[i]] + price[i]);
}
}
}
int result = sum - dp[n][sum-x];
printf("%d",result);
return 0;
}
// 暴力解法,指数级
//int main(){
// int n,x;
// scanf("%d %d",&n,&x);
// int price[n];
// for(int i = 0;i<n;i++){
// scanf("%d",&price[i]);
// }
//
// int sum = 300005;
// int start,total = 1<<n;
// for(start = 0; start<total;start++){
// int temp = 0;
// for(int i = 0;i<n;i++){
// int choose = start>>i & 0x1;
// temp += choose * price[n-i-1];
// }
// if(temp >= x){
// sum = min(sum,temp);
// }
// }
//
// printf("%d",sum);
//
// return 0;
//}
遇到的坑
-
二维动态规划的初始化问题
因为递推公式中有 i-1,要求 i 需要大于 0
但是我们没有初始化 i = 0 这一行,解决方法:
设定 i 从 1 到 n,i=0 这一行没有意义,值为 0
而 j 依然从 0 到 target -
大数组的定义问题
遇到比较大的数组如 dp[40][300000],
假如定义为局部变量存储在栈中,栈太小了会溢出,
此时需要将其定义为全局变量,存储于堆中 -
二维数组的初始化问题
请使用 memset(dp,0,sizeof(dp))