HDOJ5616 Jam‘s balance

目录

  • HDOJ5616 Jam's balance
    • 题目描述
      • 背景
      • 输入
      • 输出
    • 题解
      • 解法一
      • 解法二
      • 优化
    • 打赏

HDOJ5616 Jam’s balance

题目描述

背景

N N N个已知质量的砝码,分别询问给出的 M M M个质量能否被称出

输入

  1. 第一行输入一个变量 T T T,表示有 T T T组数据;
  2. 第二行输入一个变量 N N N,表示有 N N N个砝码;
  3. 第三行输入 N N N个变量 w 1 , w 2 , ⋯   , w n w_1, w_2, \cdots, w_n w1,w2,,wn,分别表示这 N N N个砝码的质量;
  4. 第四行输入一个变量 M M M,表示要询问的质量有 M M M个;
  5. 第五行输入 M M M个变量 u 1 , u 2 , ⋯   , u m u_1, u_2, \cdots, u_m u1,u2,,um,分别表示要询问的质量

输出

对于每组数据每个询问的质量判断并输出一行 Y E S YES YES N O NO NO

题解

解法一

定义一个数组 f [ ] f[] f[] f [ i ] f[i] f[i]表示当表示出的质量小于等于 i i i时所能表示的最大值,那么本题就可以看成是一个背包问题,而且是每个物品的体积和价值都一致的背包问题
背包问题的状态转移方程是 f [ j ] = m a x ( f [ j ] , f [ j − v [ i ] ] + w [ i ] ) f[j] = max(f[j], f[j - v[i]] + w[i]) f[j]=max(f[j],f[jv[i]]+w[i]),该问题中即为 f [ j ] = m a x ( f [ j ] , f [ j − w [ i ] ] + w [ i ] ) f[j] = max(f[j], f[j - w[i]] + w[i]) f[j]=max(f[j],f[jw[i]]+w[i]),但是该问题有一些不同,因为砝码可以放在两边,所以不是简单的价值相加,但是考虑用 w [ i ] w[i] w[i]加上前 i − 1 i - 1 i1个砝码组合出的某个方案时还是可以使用这个方程的
现在考虑相减的情况,假设要用第 i i i个砝码更新 f [ j ] f[j] f[j],那么对第 i i i个砝码的使用有两种情况,一是用前 i − 1 i - 1 i1个砝码组合出的某个方案减去 w [ i ] w[i] w[i],二是用 w [ i ] w[i] w[i]减去前 i − 1 i - 1 i1个砝码组合出的某个方案
第一种情况和相加类似,易得 f [ j ] = m a x ( f [ j ] , f [ j + w [ i ] ] − w [ i ] ) f[j] = max(f[j], f[j + w[i]] - w[i]) f[j]=max(f[j],f[j+w[i]]w[i]),但是为了防止 f [ k ] ( k > j ) f[k](k > j) f[k](k>j) f [ j ] f[j] f[j]更先更新,从而导致同一砝码使用两次, j j j应该顺序枚举
第二种情况使用 w [ i ] w[i] w[i]更新时,由于 f [ j ] f[j] f[j]表示的是不大于 j j j的最大值,所以应该用 w [ i ] w[i] w[i]减去不小于 w [ i ] − j w[i] - j w[i]j的最小值,那么还需要再定义一个数组 g [ ] g[] g[] g [ i ] g[i] g[i]表示当表示出的质量大于等于 i i i时所能表示的最小值,于是可以得到方程 f [ j ] = m a x ( f [ j ] , w [ i ] − g [ w [ i ] − j ] ) f[j] = max(f[j], w[i] - g[w[i] - j]) f[j]=max(f[j],w[i]g[w[i]j])
定义了一个新的数组,那么它也需要被维护,方程和 f f f是类似的
接着考虑到实际上只需要判断是否可以得到询问的质量,而不需要真正算出最大值和最小值,所以 f , g f , g f,g都可以换为 b o o l bool bool数组并对方程做出改变
最后考虑相加和两种相减计算的先后顺序,相加第一个,之后无论是何种相减,即使减去的方案中使用了同一砝码也会抵消,第二个是相减的情况二,这样在考虑相减的情况一时遇到同一砝码也会抵消,如果后两者反过来,则会导致统一砝码使用多次
代码如下:

#include<cstdio>
#include<cstring>
using namespace std;

const int M = 25;
const int N = 2005;

int main() {
    int t, n, m, mxx, sum;
    int w[M], v[N];
    bool f[N], g[N];

    scanf("%d", &t);

    while(t--) {
        memset(f, 0, sizeof(f));
        memset(g, 0, sizeof(g));
        g[0] = 0;

        scanf("%d", &n);
        for(int i = 1; i <= n; ++i) scanf("%d", &w[i]);
        scanf("%d", &m);
        for(int i = 1; i <= m; ++i) scanf("%d", &v[i]);

        sum = w[1];
        g[w[1]] = f[w[1]] = g[0] = f[0] = 1;     //初始化不要忘记改了

        for(int i = 2; i <= n; ++i) {
            for(int j = sum += w[i]; j > w[i]; --j) {
                f[j] |= f[j - w[i]];
                g[j] |= g[j - w[i]];
            }
            for(int j = 1; j <= w[i]; ++j) {
                f[j] |= g[w[i] - j];
                g[j] |= f[w[i] - j];
            }
            for(int j = 1, mx = sum - (w[i] << 1); j <= mx; ++j) {
                f[j] |= f[j + w[i]];
                g[j] |= g[j + w[i]];
            }
        }

        for(int i = 1; i <= m; ++i) f[v[i]] ? puts("YES") : puts("NO");
    }
    return 0;
}

解法二

接下来考虑是否可以把两种相减变成一种,核心想法还是背包问题的解法
可以考虑把相加和相减分成两个循环,先单纯考虑相加,再用方案减去 w [ i ] w[i] w[i]的方式对方案进行更新,这样就同时考虑了两种相减
代码如下:

#include<cstdio>
#include<cstring>
using namespace std;

#define il inline

const int M = 25;
const int N = 2005;

int main() {
    bool f[N];
    int t, n, m, sum;
    int w[M];

    scanf("%d", &t);

    while(t--) {
        memset(f, 0, sizeof(f));
        sum = 0, f[0] = 1;

        scanf("%d", &n);
        for(int i = 1; i <= n; ++i) scanf("%d", &w[i]);

        for(int i = 1; i <= n; ++i) {
            for(int j = sum + w[i]; j >= w[i]; --j) f[j] |= f[j - w[i]];
            sum += w[i];
        }

        for(int i = 1; i <= n; ++i) {
            int mx = sum - w[i];
            for(int j = 1; j <= mx; ++j) f[j] |= f[j + w[i]];
        }

        scanf("%d", &m);
        while(m--) {
            int x;
            scanf("%d", &x);
            f[x] ? puts("YES") : puts("NO");
        }
    }
    return 0;
}

优化

当同质量的砝码有多个时,如果看成单独的多个砝码,某些本质相同的操作会重复进行,所以不妨看成多重背包再进行二进制优化,二进制优化就是把有多个的某质量砝码依据二进制进行分组等效,如把 8 8 8个质量为 1 1 1的砝码等效质量分别为 1 , 2 , 4 , 1 1 , 2 , 4 , 1 1,2,4,1 4 4 4个砝码,等效前后能表示的质量不变,而砝码数量却下降了
可以发现这个等效本质上就是满 3 3 3 1 1 1,同时两倍质量的砝码数量加 1 1 1,直到不再可以等效
由于可能的砝码数量只有 0 , 1 , 2 0 , 1 , 2 0,1,2,所以不妨使用 b o o l bool bool数组 s s s储存砝码数量, f a l s e , t r u e false , true false,true分别表示 1 , 2 1 , 2 1,2,且 w [ i ] w[i] w[i]表示第 i i i种砝码的质量,再添加一个数组 p o s [ i ] pos[i] pos[i]表示质量为 i i i的砝码在 s s s中的下标,这样每当出现一个新质量的砝码, s s s中元素的总数 t o t tot tot就加 1 1 1
由于数量较小,对于数量为 2 2 2的砝码也可以不采用多重背包的一般方法,直接当成 2 2 2个单独砝码处理即可
代码如下:

#include<cstdio>
#include<cstring>
using namespace std;

#define il inline

const int M = 25;
const int N = 2005;

il int read() {
    int x = 0;
    char c = getchar();
    while(c > '9' || c < '0') c = getchar();
    while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
    return x;
}

int main() {
    bool s[M], f[N];
    int t, n, m, tot, sum, wei;
    int w[M], pos[N];
    memset(pos, 0, sizeof(pos));

    t = read();

    while(t--) {
        memset(f, 0, sizeof(f));
        tot = sum = 0, f[0] = 1;

        n = read();
        for(int i = 1, j; i <= n; ++i) {
            wei = read(), j = pos[wei];
            while(j && s[j]) s[j] = 0, j = pos[wei <<= 1];
            if(!j) pos[wei] = ++tot, s[tot] = 0, w[tot] = wei;
            else s[j] = 1;
        }

        for(int i = 1; i <= tot; ++i) {
            for(int j = sum += w[i]; j >= w[i]; --j) f[j] |= f[j - w[i]];
            if(s[i]) w[++tot] = w[i], s[tot] = 0;
            pos[w[i]] = 0;     //顺便重置pos,这样就不用反复memset
        }

        for(int i = 1; i <= tot; ++i)
            for(int j = 1, mx = sum - w[i]; j <= mx; ++j)
            	f[j] |= f[j + w[i]];

        m = read();
        while(m--) f[read()] ? puts("YES") : puts("NO");
    }
    return 0;
}

打赏

制作不易,若有帮助,欢迎打赏!
赞赏码

支付宝付款码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/745449.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LLM生成模型在生物蛋白质应用:ESM3

参考&#xff1a; https://github.com/evolutionaryscale/esm 报告&#xff1a;https://www.evolutionaryscale.ai/blog/esm3-release 通过GPT模型原理&#xff0c;输入蛋白质序列等模态输出预测的蛋白质序列及结构 使用 参考&#xff1a;https://colab.research.google.c…

智能扫地机,让生活电器更加便民-NV040D扫地机语音方案

一、语音扫地机开发背景&#xff1a; 随着人工智能和物联网技术的飞速发展&#xff0c;智能家居设备已成为现代家庭不可或缺的一部分。其中&#xff0c;扫地机作为家庭清洁的重要工具&#xff0c;更是得到了广泛的关注和应用。 然而&#xff0c;传统的扫地机在功能和使用上仍存…

深圳比创达EMC|EMC与EMI滤波器:在电子设备中的平衡之道

随着科技的快速发展&#xff0c;电子设备已经深入到我们生活的方方面面&#xff0c;从家用电器到工业设备&#xff0c;从通信设备到医疗仪器&#xff0c;都离不开电子技术的支持。然而&#xff0c;电子设备在带来便利的同时&#xff0c;也面临着电磁兼容&#xff08;EMC&#x…

一个很好用的地图工具的使用:思极地图,以及vue+思极地图的使用

前言&#xff1a; 随着现在国网等一部分公司的需求&#xff0c;在线地图-思极地图 出现在我们眼前&#xff0c;给我们带来了很多便利&#xff0c;这里分享下他的信息与使用。 实现效果&#xff1a; 相关资料&#xff1a; 1、官网地址 2、在线地址 3、官方api地址 实现步骤-js…

河南资信乙级预评价:人员需缴唯一社保吗?

河南资信乙级预评价中&#xff0c;人员确实需要缴纳唯一社保。以下是详细的解读和归纳&#xff1a; 一、社保唯一性的定义 社保唯一性指的是参与河南资信乙级预评价的咨询工程师&#xff08;投资&#xff09;必须在申请单位有唯一且连续的社保缴纳记录。这一要求旨在确保咨询…

鸿蒙 HarmonyOS NEXT星河版APP应用开发阶段三-热门组件使用及案例

一、样式和结果重用 介绍 /* Extend:扩展组件&#xff08;样式、事件&#xff09; Styles: 抽取通用数据、事件 Builder:自定义构建函数&#xff08;结构、样式、事件&#xff09; */Extend /* 作用&#xff1a;扩展组件&#xff08;样式、事件&#xff09; 场景&#xff1a;…

C语言 | Leetcode C语言题解之第189题轮转数组

题目&#xff1a; 题解&#xff1a; void swap(int* a, int* b) {int t *a;*a *b, *b t; }void reverse(int* nums, int start, int end) {while (start < end) {swap(&nums[start], &nums[end]);start 1;end - 1;} }void rotate(int* nums, int numsSize, int…

JavaScript创建标签式组件

我们本篇将实现下面的这个标签式组件 我们本篇将实现下面的这个标签式组件 ● 当然我们首先将我们需要的元素存储到变量中&#xff0c;方便后面使用 const tabs document.querySelectorAll(.operations__tab); //获取所有的button const tabsContainer document.querySele…

ROS CDK魔法书:点亮博客上云新技能(Python篇)

引言 在数字世界的浩瀚海洋中&#xff0c;信息与数据如同戏剧中的主角&#xff0c;舞动着无形的旋律&#xff0c;构建起信息时代的交响乐。而在这其中&#xff0c;作为一位技术领域的探索者&#xff0c;你的使命便是挥舞着编码的魔杖&#xff0c;创造和守护着这些宝贵的数字灵…

外贸邮件推送有哪些策略?如何提升转化率?

外贸邮件推送的效果怎么优化&#xff1f;邮件推送的技巧有哪些&#xff1f; 外贸邮件推送是一种有效的市场营销策略&#xff0c;可以帮助企业开拓国际市场&#xff0c;增加销售额。然而&#xff0c;成功的外贸邮件推送并不是一蹴而就的&#xff0c;需要精心策划和执行。AokSen…

【RF Transceiver】ADRV9040 THEORY OF OPERATION

工作原理 概述 GENERAL 该 ADRV9040 是一款高度集成的射频收发器&#xff0c;能够针对各种应用进行配置。该器件集成了在单个器件中提供所有发射器、流量接收机和观测接收机功能所需的所有射频、混合信号和数字模块。可编程性使该器件能够适应 TDD 模式下的许多 3G/4G/5G 蜂窝…

“论大数据处理架构及其应用”高分范文,软考高级,系统架构设计师

论文真题 大数据处理架构是专门用于处理和分析巨量复杂数据集的软件架构。它通常包括数据收集、存储、处理、分析和可视化等多个层面&#xff0c;旨在从海量、多样化的数据中提取有价值的信息。Lambda架构是大数据平台里最成熟、最稳定的架构&#xff0c;它是一种将批处理和流…

vue3使用vant4的列表vant-list点击进入详情自动滚动到对应位置,踩坑日记(一天半的踩坑经历)

1.路由添加keepAlive <!-- Vue3缓存组件&#xff0c;写法和Vue2不一样--><router-view v-slot"{ Component }"><keep-alive><component :is"Component" v-if"$route.meta.keepAlive"/></keep-alive><component…

20240626每日AI-----------创建你的第一个文心智能体平台Agent

载体 文心智能体平台Agent 注册 统一使用百度账户登录即可 创建智能体 登录后即可在左边菜单进行点击&#xff0c;创建智能体。 创建官方智能体 编写你的智能体名称等等信息

迅为RK3588开发板支持LVDS信号,标准 HDMI信号,IMIPI信号

性能强--iTOP-3588开发板采用瑞芯微RK3588处理器&#xff0c;是全新一代ALoT高端应用芯片&#xff0c;采用8nm LP制程&#xff0c;搭载八核64位CPU&#xff0c;四核Cortex-A76和四核Cortex-A55架构&#xff0c;主频高达2.4GHZ&#xff0c;8GB内存&#xff0c;32GB EMMC。 四核心…

【C++】关于虚函数的理解

深入探索C虚函数&#xff1a;原理、应用与实例分析 一、虚函数的原理二、虚函数的应用三、代码实例分析四、总结 在C面向对象编程的世界里&#xff0c;虚函数&#xff08;Virtual Function&#xff09;扮演着至关重要的角色。它不仅实现了多态性这一核心特性&#xff0c;还使得…

云层区分神经网络模型——二分类

云层区分神经网络模型——二分类 问奶奶&#xff0c;是什么让他们维护一份感情长达年&#xff0c;奶奶说那个年代什么东西坏了都会想要修&#xff0c;现在什么坏了都想着换。 安装依赖 # 要运行脚本&#xff0c;请先安装以下库&#xff1a;pip install tensorflowpip install …

健康管理系统

摘 要 随着现代社会生活节奏的加快和工作压力的增大&#xff0c;人们对健康管理的需求日益凸显。传统的健康管理方式&#xff0c;如定期体检、手动记录健康数据等&#xff0c;已经无法满足现代人对健康管理的即时性、全面性和个性化需求。因此&#xff0c;开发一款高效、便捷的…

Docker三分钟部署ElasticSearch平替MeiliSearch轻量级搜索引擎

&#x1f469;&#x1f3fd;‍&#x1f4bb;个人主页&#xff1a;阿木木AEcru (更多精彩内容可进入主页观看) &#x1f525; 系列专栏&#xff1a;《Docker容器化部署系列》 《Java每日面筋》 &#x1f4b9;每一次技术突破&#xff0c;都是对自我能力的挑战和超越。 目录 一、 …

Topaz Gigapixel AI图片无损放大软件下载安装,Topaz Gigapixel AI 高精度的图片无损放大

Topaz Gigapixel AI无疑是一款革命性的图片无损放大软件&#xff0c;它在图像处理领域开创了一种全新的可能性。 Topaz Gigapixel AI的核心功能在于能够将图片进行高精度的无损放大。虽然经过软件处理的图片严格意义上并不能算是完全无损&#xff0c;但相较于传统方法&#xf…