五个砝码问题,三种解法

来源:互联网 发布:淘宝店店铺招牌图片 编辑:程序博客网 时间:2024/06/04 20:03
5个砝码
用天平称重时,我们希望用尽可能少的砝码组合称出尽可能多的重量。
如果只有5个砝码,重量分别是1,3,9,27,81。则它们可以组合称出1到121之间任意整数重量
(砝码允许放在左右两个盘中)。
本题目要求编程实现:对用户给定的重量,给出砝码组合方案。
例如:
用户输入:
5
程序输出:
9-3-1
用户输入:
19
程序输出:
27-9+1

  要求程序输出的组合总是大数在前小数在后。

    可以假设用户的输入的数字符合范围1~121。

方法一:递归求解

可以发现,在输出的表达式中第一个输出的数不可能是负数,所以首先我们从最大的数81开始,直到得到满足题意的数。如:输入5,输出9-3-1,第一个满足的是9;输入19,输出27-9+1,第一个数是27等。确定第一个数之后再与比这个数小的数(最接近这个数的数)相加,若不满足则相减,然后取满足的运算结果继续重复之前的运算。

代码如下:

#include<stdio.h>int n;//输入的数int temp[6] = {0,1,3,9,27,81};//保存5个砝码//result保存当前运算结果,i表示当前所需最大砝码下标,//sum的作用是这样的:当我们选择81的时候,其余数之后为sum=1+3+9+27,如果81-40大于n,//则结束后面的递归。例如输入5,从砝码81开始判断,直到砝码9才满足,此时sum=1+3=4,因//为9-sum=9-4=5不大于5,所以满足,继续后面的运算。sum就是保存小于当前所选砝码的重量和。//can数组用来保存满足题意的计算过程。void fun(int result,int i,int sum,int can[]){if (result == n)//如果运算结果等于n{for (int k = 5; k > 0; k--){if (can[k] > 0){printf("+%d",can[k]);}else if (can[k] < 0){printf("%d",can[k]);}}printf("\n");}else if (result - sum > n)//判断有没必要继续后面的计算{return;}else{for (int j = i; j > 0; j--){can[i] = temp[j];//保存过程fun(result + temp[j],j - 1,sum -= temp[j],can);//相加if (i == 5)//第一个打印输出的数是正数,不可能用来相减,是i==5时开始的{continue;}can[i] = -temp[j];//保存过程fun(result - temp[j],j - 1,sum,can);//相减can[i] = 0;//都不满足,归零}}}int main(){int can[6] = {0};scanf("%d",&n);fun(0,5,121,can);//开始递归求解return 0;}

方法二:迭代法

这个看下代码应该就明白了,代码如下:

#include <stdio.h>int main(){int can[5];//每个砝码有三种状态,要么相加,要么相减,要么啥也不干int a[3] = {0,1,-1};int b[3] = {0,3,-3};int c[3] = {0,9,-9};int d[3] = {0,27,-27};int e[3] = {0,81,-81};int h,i,j,k,m,n;scanf("%d",&n);for (i = 0; i < 3; i++)for (j = 0; j < 3; j++)for (k = 0; k < 3; k++)for (m = 0; m < 3; m++)for(h = 0; h < 3; h++){if (a[i] + b[j] + c[k] + d[m] + e[h] == n){can[4] = a[i];can[3] = b[j];can[2] = c[k];can[1] = d[m];can[0] = e[h];}}for (i = 0; i < 5; i++){if (i == 0)printf("%d",can[i]);else if (can[i] > 0)printf("+%d",can[i]);else if (can[i] < 0)printf("%d",can[i]);}printf("\n");return 0;}

方法三:巧妙利用3进制

首先,为啥用3进制呢,可以看看题目这组数据,你就会发现:3^0 = 1,3^1 = 3,3^2 = 9,3^3 = 27,3^4 = 81。

然后,将输入的数转换成3进驻,如19的三进制为201,我们同时可以发现,每一个三进制位上的数表示有几个相应的砝码。如三进制201表示有

2个砝码9,一个砝码1,所以2 * 9 + 1 = 19。同样我们如果输入5,三进制为12,表示有一个砝码3,两个砝码1,所以3 + 2 * 1 = 5。但题目要求每个砝码

只用一次,那怎么办呢?你可以发现三进制每个位上只有三种可能,要么是0,要么是1,要么是2,再想想方法二,是不是明白得差不多了?三种状态如何处理呢?

首先转换成三进制,然后从末尾起查看每一位,对于第i位来讲(i从0开始)
1. 如果是1,则相当于用3的i次方1次
2. 如果是2,则相当于用3的i次方作为减法1次,并且向高位进1
3. 如果是0,则不需要用到3的i次方

如输入19,三进制为201,从最后一位开始,首先是1,则记+3^0;第二位为0,不处理;第三位为2,则记-3^2,向高位进一,那么第四位从0变成1,记+3^3。

一综合即为:3^3 - 3^2 + 3^0 = 27 - 9 + 1 = 19;

代码就不详细列出了,读者可以试试看,应该比较容易实现。

原创粉丝点击