12届蓝桥杯省赛-砝码称重
前言:
在这一篇文章中,我们主要介绍“砝码称重”这道题的解法
正文:
一、题干:
【问题描述】
你有一架天平和 N 个砝码,这 N 个砝码重量依次是 W1,W2,...,WN。
请你计算一共可以称出多少种不同的正整数重量?
注意砝码可以放在天平两边。
【输入格式】
输入的第一行包含一个整数 N。
第二行包含 N 个整数:W1,W2,W3,...,WN。
【输出格式】
输出一个整数代表答案。
【样例输入】
3
1 4 6
【输出样例】
10
【样例说明】
能称出的 10 种重量是:1、2、3、4、5、6、7、9、10、11。
1 = 1;
2 = 6 − 4 (天平一边放 6,另一边放 4);
3 = 4 − 1;
4 = 4;
5 = 6 − 1;
6 = 6;
7 = 1 + 6;
9 = 4 + 6 − 1;
10 = 4 + 6;
11 = 1 + 4 + 6。
【评测用例规模与约定】
对于 50% 的评测用例,1≤N≤15。
对于所有评测用例,1≤N≤100,N 个砝码总重不超过 100000。
二、思路:
这道题中,可以发现放入第一个砝码的时候,只能称出一个值,放入第二个砝码的时候,可以只放第二个砝码称出一个值,可以把第一个放左边第二个放右边称出一个值,可以把第一个放右边边第二个放左边又称出一个值。而第三个砝码出现的时候,我们可以根据之前得到的值加上砝码来得到新的值。总而言之,就是动态规划。
这样题目就化简为了如何用旧的值推出新的值,我们用一个一维数组来存储可以表示出的值,对每一个新的值引入的时候,我们做以下操作来推出新的值(设旧的值为j,新的值为a,数组名为b)
b[j+a]=1;(将j和a看作砝码的话,就是j和a都放右边(左物右码))
b[j-a]=1;(将j和a看作砝码的话,就是j放右边a放左边)
b[a-j]=1;(将j和a看作砝码的话,就是j放左边a放右边)
只不过这样子会放出负数,而数据范围说了砝码总重不超过100000,所以最后操作的时候我们要把所有值都加100000防止访问到负数。
以题中所给的样例为例进行演算:
放入一个砝码重量为1时(w为可以称出的重量):
w=1;
放入二个砝码重量为1,4时:
w=1+4=5;(用w=1来求)
w=1-4=-3;
w=4-1=3;
w=4;
放入三个砝码重量为1,4,6时:
w=1+6=7;(用w=1来求)
w=1-6=-5;
w=6-1=5;
w=5+6=11;(用w=1+4=5来求)
w=5-6=-1;
w=6-5=1;
w=-3+6=3;(用w=1-4=3来求)
w=-3-6=-9;
w=6-(-3)=9;
w=3+6=9;(用w=4-1=3来求)
w=3-6=-3;
w=6-3=3;
w=4+6=10;(用w=4来求)
w=4-6=-2;
w=6-4=2;
w=6;
上面所有不重复的正数(也就是标蓝的)数量就是答案:10。
思路已经明了,所以程序呼之欲出:
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int main(int argc, char const *argv[]) 5 { 6 int b[200001];//是否被称出,以及是前几个称出的 7 memset(b,0,sizeof(b)); 8 int n; 9 cin>>n; 10 int a; 11 for (int i = 1; i <= n; i++) 12 { 13 cin>>a; 14 for (int j = 0; j <= 200000; j++) 15 { 16 if(b[j]!=i&&b[j]!=0) 17 { 18 if(b[j+a] == 0)b[j+a]=i; 19 if(b[j-a] == 0)b[j-a]=i; 20 if(b[200000+a-j] == 0)b[200000+a-j]=i; 21 } 22 } 23 b[a+100000] = i; 24 } 25 int sum = 0; 26 for (int i = 100001; i <= 200000; i++) 27 { 28 if(b[i]!=0) 29 { 30 sum++; 31 } 32 } 33 cout<<sum; 34 35 return 0; 36 }
其中
1 for (int i = 1; i <= n; i++) 2 { 3 cin>>a; 4 for (int j = 0; j <= 200000; j++) 5 { 6 if(b[j]!=i&&b[j]!=0) 7 { 8 if(b[j+a] == 0)b[j+a]=i; 9 if(b[j-a] == 0)b[j-a]=i; 10 if(b[200000+a-j] == 0)b[200000+a-j]=i; 11 } 12 } 13 b[a+100000] = i; 14 }
这一部分就是核心部分,说明一下,b不像前面样例中存的是0和1,在这个程序中存的是整型变量,用来表示它可以由前b[j]个砝码称出,而b[j]!=i是为了防止重复使用一个砝码,举个例子:
b[4+6]=3;
b[4+6+6]=3;
b[4+6+6+6]=3;
如此就可以在使用i个砝码的时候,只使用前i-1个砝码了。
另外,如果称出0的重量算数吗?(比如左边放5,右边放2+3)答案是不算哈~,所以在求结果的时候要把0给排除掉。
参考博客:
https://blog.csdn.net/asbbv/article/details/117253522
后记:
感谢各位读到这,虽然是AC了但是这道题绝对有更简洁更快的方法,果然还是太菜了唉QAQ
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构