这周主要看了背包问题的博客。背包问题有多种类型:01背包,完全背包,多重背包,分组背包等。这类问题着重于对题目的分析,找到其对应的背包类型。下面总结一下这周看过的题中体会较深的题目。
1.P1049 [NOIP2001 普及组] 装箱问题
题意:有一个箱子容量为V,同时有n个物品,每个物品有一个体积。要求n个物品中,任取若干个装入箱内,使箱子的剩余空间为最小。
题解:
其实第一次看这道题时想到的是搜索,但后来仔细想了想,背包也能做,而且做起来比搜索简单,只是理解要转换一下。
题目求出最小的剩余空间,也就是要求出最大的可装重量。如果把一个物体的重量当作它的价值,那么题目就可以转变为一个基本的01背包问题。一个箱子有两种状态:装与不装。记第i个箱子重量为w[i],对于任意重量m的最大价值记为 f (m) ,于是可得状态转移方程 f(m)= max ( f ( m - w[i] ) + w[i], f (m) )。简单的01背包问题,难度不大。
- P1455 搭配购买
题意:一种搭配即为一个集合,求不超过给定价值集合的价值最大值。
题解:
这道题在做并查集练习时做过,当时做的的时候还没有01背包的概念,写的代码比较繁琐,现在看来用01背包做更加简单,于是在此整理一下。
这是一道并查集+01背包题,01背包的限制条件为买A必须买B,故可以用并查集将几个物品合成一个大物品,然后再用01背包做即可。
for(int i=1; i<=tot; i++)
for(int j=w; j>=newp[i]; j--) //滚动数组
f[j]=max(f[j],f[j-newp[i]]+newv[i]);
- The Values You Can Make
题意:有n个硬币,硬币有对应的价值,现在要挑出一些硬币组成k元,输出挑出的硬币可以组成钱的不同价值。
题解:
该题和背包比较相似,不过又加了个状态,就是是否可以组成s,那么状态dp[i][j][p]为考虑到第i个数,当前所有数的和为j,组成和为p的子集是否可能。
于是可以得到状态转移关系:
如果不使用第i个数,dp[i][j][p]=dp[i-1][j][p]
如果使用第i个数但子集不取他,dp[i][j][p]=dp[i-1][j-ci][p]
如果使用第i个数且子集取他,dp[i][j][p]=dp[i-1][j-ci][p-ci]。
代码:
#include
#include
#include
#include
#include