【问题描述】
将 1-9不重复地赋给不同的 9个元素 ,实现形如 a/bc+d/ef=g/hi 的形式: 例:1/26+5/78=4/39 1/32+5/96=7/84 (注意:1/26+5/78=4/39 和 5/78+1/26=4/39 只能算一种解) 求满足条件的解共有多少个?
【解决思路】
首先想到回溯和DFS,这里选择了类全排列的DFS。可以设置一个num数组存放这些不重复的数字,此时可以类比全排列方法,使用数组访问法或者是交换法进行排列(两种方法具体点击这里)。此处我们选择交换法,因为两者难度和效果其实相同,但是数组访问法需要多建立1-2个数组,空间稍微费一些。
而在此处的除法,会要考虑到数值类型和小数精度的问题,所以可以使用两种方法解决。
(1)Java语言中的BigDcimal类
(2)除法转换成乘法。这里选择了第二种,让大家理解方便,较为简单。
将其替换成a-f的字母,再转变成乘法公式adf+bcf==bde,其中
同时还要注意题目中要求的:1/26+5/78=4/39 和 5/78+1/26=4/39 只能算一种解,所以我们需要给定一个条件来去除一些重复的结果,这里可以在左边两个分数的分子或者分母处理,简单起见可以选择num[0]和num[3]比较大小。
【模板套用】
这道题就是一道经典的DFS、全排列或者回溯的问题,可以使用dfs全排列的模板来解决。模板具体看这里
【代码及注释】
import java.util.Scanner;
/*
*2020年6月22日
*@author:huhu
*/
public class 桥本分数式 {
/*
* 本题如果不用乘法计算,就得用BigDecimal来计算,不然精度不够,无法准确得出答案
*/
static Scanner sc = new Scanner(System.in);
static int n = 9;//共9个数字
static int res = 0;//输出的结果
public static void main(String[] args) {
long start_time = System.currentTimeMillis(); //耗时test
int num[] = new int[n];//原始数据数组
for (int i = 0; i < num.length; i++) {
num[i] = i+1;
//1~n的n个数字赋给num[0]~num[n-1]
}
dfs(num,0);
long result_time = System.currentTimeMillis() - start_time;//耗时test结果
System.out.println("共"+res+"组");
System.out.println("耗时:"+result_time+"ms");
sc.close();//关闭输入流
}
public static void dfs(int[] num,int step) {
if (step >= n-1) {
if (num[0]<num[3]) {
//避免重复
int a = num[0];//左一的分子
int b = num[1]*10+num[2];//左一分母
int c = num[3];//左二分子
int d = num[4]*10+num[5];//左二分母
int e = num[6];//右一分子
int f = num[7]*10+num[8];//右二分母
// if ((a/b)+(c/d)==(e/f)) {//不可以使用除法,会导致精度降低,程序出错
if (a*d*f+b*c*f==b*d*e) {
res++;
System.out.println(a+"/"+b+"+"+c+"/"+d+"="+e+"/"+f);
}
}
}
else {//这里的else必不可少,没有else,不管怎么样都会走到这一步。
for (int i = step; i < num.length; i++) {
swap(num,i,step);
dfs(num,step+1);
swap(num,step,i);//交换回来,还原位置,为另一种可能做准备
}
}
}
public static void swap(int[] num, int i, int j) {
/*交换法实现DFS
* 比数组访问法较好的是占用空间小一点,省去了vis数组和result数组
*/
int temp = num[i];
num[i] = num[j];
num[j] = temp;
}
}