一、问题
二、思路
首先,我们观察到带分数的特性(原数字=加数+被除数/除数),同时加数、被除数和除数所含数字正好不重复不遗漏地包括1-9这9个数。所以我们有以下两个思路:
- 从数字角度来看 ,双层循环+判断重复:一层循环加数,一层循环除数,剩下的就是被除数;再用重复判断函数来去除一些加数和除数。(该思路耗时严重,会超时)
- 从排列角度来看,全排列+分割:运用递归算法实现9个数字的全排列组合;再对每个排列“切两刀”,得到三个子排列再转换成数字,也即加数、被除数和除数。
无论是数字还是排列的思路,都需要注意限制条件: 加数<=原数字,被除数>=除数,被除数能被除数整除。如果没有这些条件,即使是用第二种思路也会超时,望注意!!!
三、代码
import java.util.Scanner;
public class Main{
static int num = 0; // 需表示成带分数的数字
static int count = 0; // 带分数种数
static int js=0; // 加数
static int bcs=0; // 被除数
static int cs=0; // 除数
public static void main(String args[]) {
int[]arr = {1,2,3,4,5,6,7,8,9};
Scanner sc = new Scanner(System.in);
num = sc.nextInt();
sc.close();
dfs(arr,0);
System.out.println(count);
// System.out.println("-----------------------------\n"+count);
}
public static void dfs(int[] arr, int n) {
int temp;
if(n >= arr.length-1) {
js=0;
// 将数组分割成加数和部分1
for(int i = 0; i < 7; i++) {
js = js*10 + arr[i];
if(js > num) {break;} // 加上限制,避免无意义循环
else {
bcs=0;
// 将部分1分割成被除数和除数
for( int j = i + 1; j < 8; j++) {
bcs = bcs * 10 + arr[j];
cs=0;
// 除数
for(int k = j + 1; k < 9; k++) {
cs = cs * 10 + arr[k];
}
// 加上条件,确定带分数
if(bcs < cs) {continue;}
else {
if((bcs % cs == 0)&(num-js== bcs/cs)) {
count++;
// System.out.printf("%d = %d + %d / %d\n",num, js, bcs, cs);// 核查算式
}
}
}
}
}
}
else {
// 用递归实现全排列
for(int i = n; i < arr.length; i++) {
temp=arr[i];arr[i]=arr[n];arr[n]=temp;
dfs(arr,n+1);
temp=arr[i];arr[i]=arr[n];arr[n]=temp;
}
}
}
}