0 1背包问题

除去h的条件

1.状态方程的确认:由0 1背包问题不难确认状态方程f[i][j] 其含义为从下标为[0-i]的物品里任意取,放进容量为j的背包,威力总和最大是多少。
2.状态的转移:
	1.不拿i:此时f[i][j] = f[i - 1][j]
	2.拿i:此时f[i][j] = f[i - 1][j - w[i]] + v[i],其中f[i - 1][j - w[i]] 为背包容量为j - w[i]时不放物品i的最大威力。
3.总结相关代码:
for(int i = 0;i <= n;i++){//从物品遍历
	for(int j = 0;j <= m;j++){
    	f[i][j] = f[i - 1][j];
        if(j >= w[i]) f[i][j] = max(f[i][j],f[i - 1][j - w[i]] + v[i]);
    }
}

加上h条件

由于当装备背包之后,如果可携带重量没有满,就可以拿一个任意重的东西。所以可以找出当h不为0时可以卡bug的时候的最大值。
		for (int k = 1; k <= n; k++) {//枚举用k来找卡bug 取k的最优解
			memset(f, 0, sizeof(f));
			for (int i = 1; i <= n; i++) {
				if (i == k) {
					for (int j = 0; j <= m + h; j++)
						f[i][j] = f[i - 1][j];
					continue;
				}
				for (int j = 0; j <= m + h; j++) {
					f[i][j] = f[i - 1][j];
					if (j >= w[i]) f[i][j] = max(f[i][j], f[i - 1][j - w[i]] + v[i]);
				}
			}
			if (h > 0) ans = max(ans, f[n][m + h - 1] + v[k]);
			else ans = max(ans, f[n][m + h]);
		}

完整ac代码

#include<bits/stdc++.h>

using namespace std;

const int N = 110;

int m, n, h;
int w[N], v[N];
int f[N][N * 2];// 0<=n,m,h<=100


int main() {
	while (cin >> n) {
		if (n == 0) break;
		cin >> m >> h;
		for (int i = 1; i <= n; i++) cin >> w[i] >> v[i];

		int ans = 0;
		for (int k = 1; k <= n; k++) {
			memset(f, 0, sizeof(f));
			for (int i = 1; i <= n; i++) {
				if (i == k) {
					for (int j = 0; j <= m + h; j++)
						f[i][j] = f[i - 1][j];
					continue;
				}
				for (int j = 0; j <= m + h; j++) {
					f[i][j] = f[i - 1][j];
					if (j >= w[i]) f[i][j] = max(f[i][j], f[i - 1][j - w[i]] + v[i]);
				}
			}
			if (h > 0) ans = max(ans, f[n][m + h - 1] + v[k]);
			else ans = max(ans, f[n][m + h]);
		}
		cout << ans << endl;
	}
	return 0;
}