背包问题

01背包

1.记忆化搜索+dfs

//记忆化搜索+dfs
int rec(int i, int j) {
	if (dp[i][j] >= 0)//已经计算过的就可以使用之前的值
		return dp[i][j];
	int res;
	if (i == n)res = 0;//0-n-1,第n个当然不能放了
	else if (j < w[i])res = rec(i + 1, j)//不能放的时候第i个最大价值等于i+1的
	else res = max(rec(i + 1, j), rec(i + 1, j - w[i]) + v[i]);
	return dp[i][j] = res;//记忆化
}

2.dp[i][j]为从第i个物品开始挑选总重小于j时,总价值的大小

物品从0-n-1编号

dp[n][j]=0;

dp[i][j]= dp[i+1][j](j< w[i])

dp[i][j]= max(dp[i+1][j],dp[i+1][j-w[i]]+v[i])(其他)

要求i必须先求出i+1,所以i是逆序

for(int i=n-1;i>=0;i--)
for (int j = 0; j <= w; j++) {
	if (j < w[i])
		dp[i][j] = dp[i + 1][j];
	else
		dp[i][j] = max(dp[i + 1][j], dp[i + 1][j - w[i]] + v[i]);
}
cout << dp[0][w] << endl;

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

dp[1][j]=dp[0][j]=0;

dp[i+1][j]=dp[i][j];

dp[i+1][j]=max(dp[i][j],dp[i][j-w[i]]+v[i])

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]);
	}
}
cout << dp[n][w];

4.滚动数组优化空间(常用)

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]);
	}
}
cout << dp[n] << endl;

完全背包

原理:

dp[i+1][j]的计算中选k个的情况,与在dp[i+1][j-w[i]]中的k-1个情况完全相同,所以dp[i+1][j]可由dp[i+1][j-w[i]]的计算得到

max{dp[i][j-kw[i]]+kv[i]|0<=k}
=max(dp[i][j],max{dp[i][j-kw[i]]+kv[i]|k>=1})
=max(dp[i][j],max{dp[i][j-w[i]-kw[i]]+kv[i]|k>=0}+v[i])
=max(dp[i][j],dp[i+1][j-w[i]]+v[i])

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 + 1][j - w[i]] + v[i]);
	}
}
cout << dp[n][w];

滚动数组优化

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]);
	}
}
cout<<dp[w];
原文地址:https://www.cnblogs.com/ACMerLwy/p/11268704.html