【砝码称重】

题目

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;
}
相关推荐
卷福同学36 分钟前
【AI编程】AI+高德MCP不到10分钟搞定上海三日游
人工智能·算法·程序员
mit6.82437 分钟前
[Leetcode] 预处理 | 多叉树bfs | 格雷编码 | static_cast | 矩阵对角线
算法
皮卡蛋炒饭.1 小时前
数据结构—排序
数据结构·算法·排序算法
??tobenewyorker2 小时前
力扣打卡第23天 二叉搜索树中的众数
数据结构·算法·leetcode
贝塔西塔2 小时前
一文读懂动态规划:多种经典问题和思路
算法·leetcode·动态规划
众链网络3 小时前
AI进化论08:机器学习的崛起——数据和算法的“二人转”,AI“闷声发大财”
人工智能·算法·机器学习
3 小时前
Unity开发中常用的洗牌算法
java·算法·unity·游戏引擎·游戏开发
飒飒真编程4 小时前
C++类模板继承部分知识及测试代码
开发语言·c++·算法
GeminiGlory4 小时前
算法练习6-大数乘法(高精度乘法)
算法
熬了夜的程序员5 小时前
【华为机试】HJ61 放苹果
算法·华为·面试·golang