题目
Bitset做法代码
cpp
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
bitset<N*2> bs;
int main()
{
bs.set(100000);
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++)
{
int x;
scanf("%d", &x);
bs = bs | bs << x | bs >> x; //bs << x 每位向高索引方向移动x,意味着之前的每个值都加了x,把bool值带到的新的高位(超出舍弃)
}
printf("%d", bs.count() / 2);
}
//注意 bs = 00000, bs.set(0)后是 00001(与我们的直觉相反,但是反过来理解即可)
背包做法代码
cpp
#include <bits/stdc++.h>
using namespace std;
const int N = 110, M = 1e5+10, off = M;
int w[N];
int f[N][2*M];
int n, m;
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", w+i), m += w[i];
f[0][0+off] = 1;
for(int i = 1; i <= n; i++)
{
for(int j = -m; j <= m; j++)
{
f[i][j+off] = f[i-1][j+off];
if(j - w[i] >= -m) f[i][j+off] |= f[i-1][j-w[i]+off];
if(j + w[i] <= m) f[i][j+off] |= f[i-1][j+w[i]+off];
}
}
int res = 0;
for(int i = 1; i <= m; i++)
{
res += (f[n][i+off]);
}
printf("%d", res);
}
不用偏移量,带绝对值的做法代码
- 绝对值相同的正负值是可以统一存储在一个空间的
- 因为这两种是可以同时做到的
- 之前的做法是,我们需要负值,就去负值+off那里找;现在的做法是去对应的正值那里找
cpp
#include <bits/stdc++.h>
using namespace std;
const int N = 110, M = 2e5 + 10;
int sum;
int n;
int w[N];
bool f[N][M];
int main() {
cin>>n;
for (int i = 1; i <= n; i++)
{
scanf("%d", &w[i]);
sum+=w[i];
}
f[0][0]=true;
for (int i = 1; i <= n;i++)
for (int j = 0; j <=sum;j++)
f[i][j]=f[i-1][j]||f[i-1][j+w[i]]||f[i-1][abs(j-w[i])];
//只要有一个非空,f[i][j]就非空
int ans = 0;
for (int i = 1; i <=sum;i++)
if(f[n][i])ans++;//不为零说明可以选出这个质量的砝码
cout << ans;
return 0;
}
因此没有必要开两倍,我们存的大小的应该等于正数数目,大于最大值的都非法
cpp
#include <bits/stdc++.h>
using namespace std;
const int N = 110, M = 1e5 + 10;
int sum;
int n;
int w[N];
bool f[N][M];
int main() {
cin>>n;
for (int i = 1; i <= n; i++)
{
scanf("%d", &w[i]);
sum+=w[i];
}
f[0][0]=true;
for (int i = 1; i <= n;i++)
for (int j = 0; j <=sum;j++)
{
f[i][j]=f[i-1][j]||f[i-1][abs(j-w[i])];
if (j + w[i] <= sum) f[i][j] |= f[i - 1][j + w[i]];
}
//只要有一个非空,f[i][j]就非空
int ans = 0;
for (int i = 1; i <=sum;i++)
if(f[n][i])ans++;//不为零说明可以选出这个质量的砝码
cout << ans;
return 0;
}