【砝码称重】

题目

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;
}
相关推荐
万岳科技系统开发28 分钟前
从源码优化外卖配送系统:算法调度、智能推荐与数据分析应用
算法·数据挖掘·数据分析
信奥卷王3 小时前
[GESP202503 五级] 原根判断
java·数据结构·算法
兮山与3 小时前
算法4.0
算法
nju_spy3 小时前
力扣每日一题(二)任务安排问题 + 区间变换问题 + 排列组合数学推式子
算法·leetcode·二分查找·贪心·排列组合·容斥原理·最大堆
初听于你3 小时前
高频面试题解析:算法到数据库全攻略
数据库·算法
翟天保Steven3 小时前
ITK-基于Mattes互信息的二维多模态配准算法
算法
代码对我眨眼睛3 小时前
226. 翻转二叉树 LeetCode 热题 HOT 100
算法·leetcode·职场和发展
黑色的山岗在沉睡4 小时前
LeetCode 494. 目标和
算法·leetcode·职场和发展
haoly19897 小时前
数据结构和算法篇-线性查找优化-移至开头策略
数据结构·算法·移至开头策略
学Linux的语莫11 小时前
机器学习数据处理
java·算法·机器学习