背包问题详细分析

首先是01背包(1):奋斗奋斗

【题目描述】有n个重量和价值分别是wi,vi的物品。从这些物品中挑选出总重量不超过W的物品,求所有挑选方案中价值总和的最大值。


限制条件:(PS限制条件不同,动态方程也不同)

1 <= n <= 100;

1 <= wi,vi <= 100;

1 <= W <= 10000;//此处W较大,而wi,vi较小


输入

n = 4

(w,v)={(2,3),(1,2)(3,4),(2,2)}

W = 5


输出

7(选择第0,1,3号物品)


【分析一】

dp[i+1][j]:从0到i这i+1个物品中选出总重量不超过j的物品时总价值的最大值

dp[0][j]=0;

            | dp[i][j]                            (j<w[i];

dp[i+1][j]= |

            | max(dp[i][j], dp[i][j-w[i]+v[i]})  (其他)。

void solve(){
	for(int i = 0; i < n; i++){
		for(int j = 0; j <= W; j++){
			if(j < w[i])
				dp[i+1][j] = dp[i][j];
			else
				dp[i+1][j] = max(dp[i][j], dp[i][j-w[i]+v[i]]); 
		}
	}
	printf("%d\n", dp[n][W]); 
}

【分析二】

void solve(){
	for(int i = 0; i < n; i++){
		for(int j = W; j >= w[i]; j--){//逆序 
			dp[j] = max(dp[j], dp[j- w[i]] + v[i]);
		}
	}
	printf("%d\n", dp[W]); 
}


01背包(2):偷笑偷笑

还记得我们前面的条件吗?在这里,要把限制条件换一下

1 <= n <= 100

1 <= wi <= 10^7

1 <= vi <= 100

1 <= W <= 10^9


【分析】

dp[i+1][j]:=前i个物品中挑选出价值总和为j时总质量的最小值(不存在时就是一个充分大的数值INF)

初始值

dp[0][0] = 0;

dp[0][j] = INF;

此外,前i个物品中挑选出机制总和为j时,有

前i-1个物品中挑选价值总和为j的部分

前i-1个物品中挑选价值总和为j-v[i]的部分,然后再选中第i个物品

这两种方法之一,所以就能得到

dp[i+1][j] = min(dp[i][j], dp[i][j-v[i] + w[i];

这一递推式。最终的答案就在应以=于令dp[n][j] <= W的最大的j。


int dp[MAX_N+1][MAX_N * MAX_V + 1];//dp数组 
void solve(){
	fill(dp[0], dp[0] + MAX_N * MAX_V +1, INF);//此处需自己写出代码
	dp[0][0] = 0;
	for(int i = 0; i < n; i++){
		for(int j = 0; j < MAX_N * MAX_V; j++){
			if(j < v[i]){
				dp[i+1][j] = dp[i][j];
			}else{
				dp[i+1][j] = min(dp[i][j], dp[i][j-v[i]] + w[i]);
			}
		}
	} 
	int res = 0;
	for(int i = 0; i <= MAX_N * MAX_V; i++)
		if(dp[n][i] <= W) 
			res = i;
	printf("%d\n", res);
}


完全背包:安静安静

【题目描述】有n个重量和价值分别是wi,vi的物品。从这些物品中挑选出总重量不超过W的物品,求所有挑选方案中价值总和的最大值。在这里,每种物品可以挑选任意多件。


限制条件:

1<=n<=100

1<=wi,vi<=100

1<=W<=10000


输入

n = 3

(w, v) = {(3,4), (4,5), (2,3)}

W = 7


输出

10(0号物品选1个,2号物品选2个)


【分析一】

令dp[i+1][j]:=从前i种物品中挑选总重不超过j时总价值的最大值。

dp[0][j]=0;

             | max{dp[i-k*w[i]] + k*v[i]      | 0<=k;}

dp[i+1][j] = | 

             | max{dp[i][j-k*w[i]] + k*v[i]   | 0<=k;}

void solve(){
	for(int i = 0; i < n; i++){
		for(int j = 0; j <= W; j++){
			for(int k = 0; k*w[i] <= j; k++){
				dp[i+1][j] = max(dp[i+1][j], dp[i][j-k*w[i]] + k*v[i]);
			}
		}
	}
	printf("%d\n", dp[n][W]); 
}

【分析二】

void solve(){
	for(int i = 0; i < n; i++){
		for(int j = w[i]; j <= W; j++){//顺序 
			dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
		}
	}
	printf("%d\n", dp[W]); 
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值