Contest100000631 - 《算法笔记》11.7小节——动态规划专题->背包问题

题目链接

A 装箱问题

  1. 从 n 件物品中选取若干件装入箱子,求箱子最后剩余空间的最小值,即求箱子内物品总体积的最大值。
  2. 本题为 01 背包问题,将物品的体积同时看作价值。用 dp[i][v] 表示前 i 件物品恰好装入容量为 v 的箱子时物品总体积的最大值。在求解 dp[i][v] 时,考虑对第 i 件物品的选择策略:①不放第 i 件物品,那么问题转化为前 i-1 件物品恰好装入容量为 v 的箱子所能获得的最大体积;②放第 i 件物品,那么问题转化为前 i-1 件物品恰好装入容量为 v-v[i] 的箱子所能获得的最大体积。故状态转移方程为dp[i][v]=max\left \{ dp[i-1][v],dp[i-1][v-v[i]]+v[i] \right \}\left ( 1\leqslant i\leqslant n,v[i]\leqslant v\leqslant V \right )边界条件为:dp[0][v]=0\left ( 0\leq v\leqslant V \right ),最后枚举 i 在1~n 范围内的 dp[i][V],取其最大值max,V-max 即为箱子最后剩余空间的最小值。时间复杂度和空间复杂度均为 O\left ( nV \right )
  3. 考虑对空间进行优化,使用一维数组,此时对 v 的枚举必须为逆序。参考代码如下。
#include
#include
using namespace std;
const int MAXN = 20010;

int dp[MAXN], w[50];
int V, n;

int main() {
	cin >> V >> n;
	for (int i = 1; i <= n; i++)
		cin >> w[i];
	fill(dp, dp + MAXN, 0);
	for (int i = 1; i <= n; i++)
		for (int v = V; v >= w[i]; v--)
			dp[v] = max(dp[v], dp[v - w[i]] + w[i]);
	cout << V - dp[V] << endl;
	return 0;
}

B 采药

  1. 本题即为标准的 01 背包问题。参考代码如下。
#include
#include
using namespace std;

const int MAXT = 1010;
const int MAXM = 110;
int T, M;
int dp[MAXT], w[MAXM], c[MAXM];

int main() {
	cin >> T >> M;
	for (int i = 1; i <= M; i++)
		cin >> w[i] >> c[i];
	fill(dp, dp + MAXT, 0);
	for (int i = 1; i <= M; i++)
		for (int v = T; v >= w[i]; v--)
			dp[v] = max(dp[v], dp[v - w[i]] + c[i]);
	cout << dp[T] << endl;
	return 0;
}

C 货币系统

  1. 本题为完全背包问题,但是和原始的背包问题不同,这里是求方案数。用 dp[i][v] 表示用前 i 种货币能表示 v 数量钱的方案数,则对第 i 种货币有选和不选的策略,故总的方案数为二者之和。因此可得状态转移方程为dp[i][v]=dp[i-1][v]+dp[i][v-w[i]]\left ( 1\leqslant i\leqslant n,w[i]\leqslant v\leqslant V \right ),边界条件为dp[0][v]=0,dp[1][v]=1\left ( 0\leqslant v\leqslant V \right )。同样也可以改写成一维形式,但是必须正向枚举,此时状态转移方程为 dp[v]=dp[v]+dp[v-w[i]],边界条件为dp[v]=\left\{\begin{matrix} 0,\left ( 0<v<=V \right )\\ 1,\left ( v=0 \right ) \end{matrix}\right.。参考代码如下。
#include
#include
using namespace std;
const int MAXN = 10010;

int V, N, w[30];
long long dp[MAXN];

int main() {
	while (cin >> V >> N) {
		for (int i = 1; i <= V; i++)
			cin >> w[i];
		fill(dp, dp + MAXN, 0);
		dp[0] = 1; //当 v - w[i] == 0 时,是一种货币选择方案,故此边界条件为 1
		for (int i = 1; i <= V; i++)
			for (int v = w[i]; v <= N; v++)
				dp[v] = dp[v] + dp[v - w[i]];
		cout << dp[N] << endl;
	}
	return 0;
}

 

你可能感兴趣的:(动态规划,背包,Codeup)