【問題描述】
將 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;
}
}