【砝码称重】

题目

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;
}
相关推荐
寂静山林2 小时前
UVa 10228 A Star not a Tree?
算法
Neverfadeaway2 小时前
【C语言】深入理解函数指针数组应用(4)
c语言·开发语言·算法·回调函数·转移表·c语言实现计算器
Madison-No73 小时前
【C++】探秘vector的底层实现
java·c++·算法
Swift社区3 小时前
LeetCode 401 - 二进制手表
算法·leetcode·ssh
派大星爱吃猫3 小时前
顺序表算法题(LeetCode)
算法·leetcode·职场和发展
liu****3 小时前
8.list的模拟实现
linux·数据结构·c++·算法·list
地平线开发者4 小时前
征程 6 | 征程 6 工具链如何支持 Matmul/Conv 双 int16 输入量化?
算法·自动驾驶
程序员大雄学编程5 小时前
「深度学习笔记4」深度学习优化算法完全指南:从梯度下降到Adam的实战详解
笔记·深度学习·算法·机器学习
小O的算法实验室6 小时前
2022年ASOC SCI2区TOP,基于竞争与合作策略的金字塔粒子群算法PPSO,深度解析+性能实测,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进
南莺莺6 小时前
邻接矩阵的基本操作
数据结构·算法··邻接矩阵