题目描述 Description
设有一个没有刻度的天平,可以用来称量
任务一:设计n个砝码的重量,用它们能称出尽可能多的连续整数重量。例如n=2时,设计两个砝码的重量分别为1和3,可称重为1、2、3、4的连续重量。
任务二:给出一个重量x(一定能在上面的最优方案下的n个砝码称出),试给出称出x的方案。如在上例中,要称出x=2的方案,方法为2+1:3;称出x=4的方案,方法为:4:1+3,称出x=1的方案为1:1.注意物体放在左边。
输入输出格式 Input/output
输入格式:
键盘输入一行,包括两个数n和x,中间用一个空格隔开。
输出格式:
屏幕输出两行,一行为n个砝码的重量(从小到大,每个数之间用一个逗号隔开),第二行为称出x的方案。
键盘输入一行,包括两个数n和x,中间用一个空格隔开。
输出格式:
屏幕输出两行,一行为n个砝码的重量(从小到大,每个数之间用一个逗号隔开),第二行为称出x的方案。
输入输出样例 Sample input/output
样例测试点#1
输入样例:
2 2
输出样例:
1,3
2+1:3
样例测试点#2
输入样例:
2 4
输出样例:
1,3
4:1+3
思路:
①从这题的任务一中不难推导:当n=1时,砝码最优解为1;当n=2时,砝码最优解为1、3;当n=3时,砝码最优解为1、3、9,通过三个例子,我们大概可以得到这样一个结论:砝码的最优解与n有很紧密的相关性,砝码重量为3的0到n-1次方,接下来就用实践检验这个结论。
②由于我们的砝码只有n个,并且重量为3的0到n-1次方,所以x必然要用这些砝码表示,不与其他数字有关,并且只能用这些砝码的和或差表示,例如7=1+9-3;2=3-1。当初我最初的想法是用DFS,搜索完每一个砝码,判断是用减号还是加号,最后记录最优解,但由于这题数据范围不确定,n太大了肯定会超时,况且这和数论关系不大,所以必须要想一个简单点的方法。
③通过观察可以发现,当x除以3时,如果余数是1,意味着要在砝码盘放上1这个砝码;当x除以3时,如果余数是2,意味着要在物盘放上1这个砝码;如果除以3余数为0,就不用放1这个砝码。同理,把x除以3后四舍五入后再除以3,根据余数判断3这个砝码的位置;再把x除以3后四舍五入再除以3后更加余数判断9这个砝码的位置,以此类推…
代码如下:
1 #include <stdio.h> 2 int main() 3 { 4 int A[10],B[10]; 5 int n,x;//n个砝码,要称重量x 6 int i,j;//循环兄弟 7 int s;//备份用变量 8 bool first; 9 scanf("%d%d",&n,&x); 10 printf("%d",A[0]=1);//无论n为何值,第一个砝码必定为1 11 /*===================================================*///解决任务一 12 for(i=1;i<n;i++) 13 { 14 printf(",%d",A[i]=A[i-1]*3); 15 printf(" "); 16 } 17 /*===================================================*/ 18 s=x; 19 for(i=0;i<n;i++) 20 { 21 if((s+A[i])%A[i+1]==0) 22 { 23 B[i]=1; 24 s=s+A[i]; 25 continue; 26 } 27 if((s-A[i])%A[i+1]==0) 28 { 29 B[i]=-1; 30 s=s-A[i]; 31 continue; 32 } 33 A[i]=0; 34 } 35 printf("%d",x); 36 for(i=0;i<n;i++) 37 { 38 if(B[i]>0) 39 { 40 printf("+%d",A[i]); 41 } 42 } 43 printf(":"); 44 first=true; 45 for(i=0;i<n;i++) 46 { 47 if(B[i]<0) 48 { 49 if(!first) 50 { 51 printf("+"); 52 } 53 printf("%d",A[i]); 54 first=false; 55 } 56 } 57 printf(" "); 58 return 0; 59 }