如果只有5个砝码,重量分别是1,3,9,27,81
则它们可以组合称出1到121之间任意整数重量(砝码允许放在左右两个盘中)。
1 3 9 27 81
本题目要求编程实现:对用户给定的重量,给出砝码组合方案。
例如:
用户输入:
5
程序输出:
9-3-1
用户输入:
19
程序输出:
27-9+1
要求程序输出的组合总是大数在前小数在后。
可以假设用户的输入的数字符合范围1~121。
分析:
暴力解决的话:、
问题在于,什么时候该用减号?什么时候该用加号?
如果全部去试一试的话,肯定得不到最优解。
分析秤砣:1 、3、9、27、81: 刚好都是3的倍数
用小规模问题去找规律
1 = 1
2 = 3-1
3 = 3
4 = 3+1
5 = 9-3-1 这里5为什么要用到-号。因为。9之前的所有数都加起来都不够5。用到减 9-4等于5 4 = 3+1
6 = 9 -3 这里 9 - 3 等于6,同理。9之前的所有数都已经不够等出6了
7 = 9-3+1 这里 相当于 9-2 等于7 2=3-1
8 = 9-1
结果。当一个数。比如5 1+3已经不能满足 5 的和,所以使用 比5 大一点点的 9 去减得到
1+3 = 4 :::::: 9 /2 =4
1+3+9 = 13 ::::::: 27/2 =13
1+3+9+27 ::::::::: 81/2 =27
规律 。
当一个数大于比他大一点的砝码的一半时。 需要通过减法得到最终值。
import java.util.Scanner;
public class Main {
public static void main(String[] args){
Scanner input = new Scanner(System.in);
System.out.println(f(input.nextInt()));
}
//减法交换定律。6-(5+3-1),把括号去掉需要更换正负号
public static String reve(String str){
str=str.replace('+','#');
str=str.replace('-','+');
str=str.replace('#','+');
return "-"+str;
}
public static String f(int n){
int a = 1;
while(a<n)a=a*3;
if(a==n)return a+"";
int b = a/2;
//判断该使用什么计算方式
if(n<=b){
return a/3+"+"+f(n-a/3);
}else{
return a+reve(f(a-n));
}
}
}
数学方式
3 进制 加 辗转 相除法
例如 19 的 3 进制 是 2 0 1
分别代表 2个 9 、 1个1、 相加 但是 砝码 9只有1个
改进下辗转相除法
当余数为2时。显然砝码是不会有2的,
我们选择将商加1 让余数 当 -1。 潜台词,,减去-1
import java.util.ArrayList;
public class Test
{
public static void main(String[] args){
for(int i=1;i<100;i++){
System.out.println(i+":"+f(i));
}
}
public static String f(int n){
String s = "";
int q = 1;
while(n>0){
int sh = n/3;
int mod = n%3;
if(mod==1){
s = "+"+q+s;
}else if(mod==2){
s = "-"+q+s;
sh++;
}
n = sh;
q *=3;
}
return s.substring(1);
}
}