题目
这是蓝桥杯2016年第七届省赛B组合C组都有的一个结果填空题:
凑算式
B DEF
A + --- + ------- = 10
C GHI
(如果显示有问题,可以参见【图1.jpg】)
这个算式中A~I代表1~9的数字,不同的字母代表不同的数字。
比如:
6+8/3+952/714 就是一种解法,
5+3/1+972/486 是另一种解法。
这个算式一共有多少种解法?
注意:你提交应该是个整数,不要填写任何多余的内容或说明性文字。
分析
因为这是一个结果填空,所以不用过于考虑性能,可以直接用暴力递归求全排列然后验证的方式来完成,9个数字的全排列是9!=362880,是肯定能在秒内完成的。
因此只需在算法思维(递归)训练:输出字符串字符的全排列的基础上稍加修改就行了。
代码
/**
* 凑算式
* A+B/C+DEF/GHI=10,A~I可以是1~9的任意不同数字
*
* 暴力求解实际就是1~9的全排列,然后验证某一种排列是否能凑成算式
* */
public class 凑算式 {
static int res;
public static void main(String[] args) {
String s = "123456789";
// 全排列
permutation(s.toCharArray(), 0);
System.out.println(res);
}
//每一段全排列,都是将每个字符换到前面,求后面段的全排列
//index代表0~index-1都已确认排列,[index,n-1]待排列
private static void permutation(char[] arr, int index) {
//至于什么时候输出,要考虑清楚
if (index == arr.length) {
// 算式凑成功了,打印并计数
if (Double.parseDouble(arr[0] + "") +
Double.parseDouble(arr[1] + "") / Double.parseDouble(arr[2] + "") +
(Double.parseDouble(arr[3] + "") * 100 + Double.parseDouble(arr[4] + "") * 10 + Double.parseDouble(arr[5] + "")) /
(Double.parseDouble(arr[6] + "") * 100 + Double.parseDouble(arr[7] + "") * 10 + Double.parseDouble((arr[8] + ""))) == 10.0) {
// System.out.println(String.valueOf(arr));
res++;
}
}
//现在index之前的字符都已就位,把之后的每个字符都交换到index这个位置
for (int k = index; k < arr.length; k++) {
//尝试交换
swap(arr, index, k);
//交换之后index这个位置就定好了,接下来的事就是递归去解决index+1位置开始的全排列就好了
permutation(arr, index + 1);
// 前面我们尝试交换,把全排列求出来了,交换时只尝试了一个字符,因此for循环继续之前要换回来,继续尝试交换下一个字符
swap(arr, index, k);
}
}
private static void swap(char[] arr, int index, int k) {
char tmp = arr[k];
arr[k] = arr[index];
arr[index] = tmp;
}
}
陷阱
注意此题验算算式时,必须用double,因为题目中说6+8/3+952/714
是正确的算式,但是直接System.out.println(6+8/3+952/714);
输出的是9,这说明全部做整数运算是不对的。
再来验证System.out.println(6+8.0/3+952.0/714);
结果是10.0
,这说明我们需要在除法运算中使用浮点数。
成功避开此坑才能得到正确答案。