100 可以表示为带分数的形式:100=3+69258/714
还可以表示为:100=82+3546/197
注意特征:带分数中,数字 1∼9分别出现且只出现一次(不包含 0)。
类似这样的带分数,100有 11 种表示法。
输入格式
一个正整数。
输出格式
输出输入数字用数码 1∼9 不重复不遗漏地组成带分数表示的全部种数。
数据范围
1≤N<10^6
输入样例1:
100
输出样例1:
11
输入样例2:
105
输出样例2:
6
解题代码:
import java.util.Arrays;
import java.util.Scanner;
public class Main {
static int n, res;
static boolean[] st = new boolean[20];
static boolean[] backup = new boolean[20];
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt();
dfsA(0, 0);
System.out.println(res);
}
public static void dfsA(int u, int a) {
if (a == n) return;
dfsC(u, a, 0);//如果说a是满足情况的,那么我们就枚举一下c,后面那个0表示c的大小
for (int i = 1; i <= 9; i++) {//枚举一下当前这个位置可以用哪些数字
if (!st[i]) {
st[i] = true;
dfsA((u + 1), a * 10 + i);//如果这个数没有被用过,那么我们就加上它,并且dfs下一层
st[i] = false;//恢复现场,回溯一下
}
}
}
public static void dfsC(int u, int a, int c) {//x表示我们已经用了多少数字
if (u == 10) return;//十个数字已全部被用掉了
if (check(a, c)) res++;//判断这样的c是否符合条件
for (int i = 1; i <= 9; i++) {//否则我们将c从1到9全部1枚举一遍
if (!st[i]) {
st[i] = true;
dfsC((u + 1), a, c * 10 + i);//如果这个数没用过,那么我们就把它放在c的后面,继续dfs下一层
st[i] = false;
}
}
}
public static boolean check(int a, int c) {
int b = n * c - a * c;//计算b
if (a <= 0 || b <= 0 || c <= 0) return false;
// 深拷贝st数组到backup数组
System.arraycopy(st, 0, backup, 0, st.length);
while (b > 0) {
int x = b % 10;//取它的每一位,用来更新一下用过的数字
if (x == 0 || backup[x]) return false;
backup[x] = true;
b /= 10;//删除掉这个已经被选中的数字
}
for (int i = 1; i <= 9; i++) {//遍历一下,判断每个数
if (!backup[i]) return false;
}
return true;
}
}
解题思路:
设n=a+b/c,这样我们可以将公式简化为 n*c=a*c+b,即b = n*c-a*c
这样我们只需要枚举a和c即可,b可以通过公式推导。
但是在check函数中需要注意,因为不能改变st数组的元素,所以我们需要开一个新的数组以便在检查完b后恢复st数组状态。但是如果使用'backup = Arrays.copyOf(st,st.length);'方法就会发生错误,因为这行代码只是将st数组的内容复制到backup数组中,但是这种复制是浅复制,也就是说,数组中的元素引用并没有被复制,而是备份数组和原数组指向了同一块内存。这意味着,当你在backup数组中修改元素时,也会影响到st数组中对应的元素。所以需要使用深拷贝。