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;
//}

遇到的坑

  1. 二维动态规划的初始化问题

    因为递推公式中有 i-1,要求 i 需要大于 0
    但是我们没有初始化 i = 0 这一行,

    解决方法:
    设定 i 从 1 到 n,i=0 这一行没有意义,值为 0
    而 j 依然从 0 到 target

  2. 大数组的定义问题

    遇到比较大的数组如 dp[40][300000],
    假如定义为局部变量存储在栈中,栈太小了会溢出,
    此时需要将其定义为全局变量,存储于堆中

  3. 二维数组的初始化问题

    请使用 memset(dp,0,sizeof(dp))

posted @ 2023-05-22 22:19  chuxin_jian  阅读(78)  评论(0)    收藏  举报