AcWing 3417. 砝码称重
原题链接
中等
作者:
ITNXD
,
2021-04-29 14:05:02
,
所有人可见
,
阅读 390
详细请查看注释
参考代码:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 110, M = 2e5 + 10, B = M / 2;
int n, m, w[N];
bool f[N][M];
/*
有限制的选择问题! 本质就是背包问题!
状态表示:f[i][j]表示前i个物品中选且总重量为j的所有方案的集合的! 属性:是否合法 bool值!
状态计算:
选 w[i]:
放左边(-w[i]):f[i - 1][j + w[i]]
放右边(+w[i]):f[i - 1][j - w[i]]
不选w[i]:f[i - 1][j]
最终状态:f[i][j] = f[i - 1][j] | f[i - 1][j - w[i]] | f[i - 1][j + w[i]]
最终答案:f[n][1] ~ f[n][m]的合法个数!
注意:总重量范围为 [-m, m],因此可以通过添加偏移量使数组下标变为正数!
由于:砝码左右交换的结果正数和负数是一个方案,因此可以只考虑一半即可![0, m]
*/
int main(){
cin >> n;
for(int i = 1; i <= n; i ++) cin >> w[i], m += w[i];
f[0][0] = true;
for(int i = 1; i <= n; i ++)
for(int j = 0; j <= m; j ++){
// f[i][j] = f[i - 1][j];
// if(j + w[i] <= m) f[i][j] |= f[i - 1][j + w[i]];
// f[i][j] |= f[i - 1][abs(j - w[i])];
// 或者直接这样,j + w[i]大于m也不影响,f[i][>m]一定为false!
f[i][j] = f[i - 1][j] | f[i - 1][j + w[i]] | f[i - 1][abs(j - w[i])];
}
int res = 0;
for(int i = 1; i <= m; i ++) res += f[n][i];
cout << res << endl;
return 0;
}