题目
下图的乘法竖式中,每一个星号代表一个数位。若出现的数字有且仅有2, 3, 5, 7四种,你能将此竖式完全还原吗?
进一步,若将题目中的2, 3, 5, 7改为其它互异的四个数字,还存在要求的乘法竖式吗?
进一步,若将题目中的2, 3, 5, 7改为其它互异的多个(2~10)数字,还存在要求的乘法竖式吗?
算法描述
针对基本问题,需要采用深度优先算法,在2, 3, 5, 7四个数字中选取所有的乘数对,并对其进行判断是否满足条件,如果满足条件,则进行打印。
针对第二个问题,需再套一层回溯算法,在0~9内选出所有4个不同的数的组合,再调用第一个问题中的函数进行寻找符合条件的乘数对。
在程序中,运算的数字存储在数组中,如365存储在a[3]中,a[0]=5,a[1]=6,a[2]=3,用代码表示为int[] a=new int[]{5,6,3}。
在对三位数乘两位数分派数字时,先在int[] merge=new int[5]中分配,然后取前三位拆分为第一个乘数,取后二位拆分为第二个乘数。
分配数字的来源是int[] stock中的,stock的默认值为{2,3,5,7}。
方法void show(int[] a)表示将数组a以乘数的形式打印出来,如int[] a=new int[]{5,6,3},show(a)的结果为365。
boolean isProper(int x)用于检测某个数值是否在要求的stock中出现。
boolean isProper(int[] a, int[] b)用于检查a和b相乘,是否满足条件,即运算中出现的数字是否在stock中。
void fun(int k)用于将stock中的数字分配到乘数对中,并在所有可能性中找到符合条件的乘数对并将其打印出来。
void fun2(int j, int k)用于在0~9中选择四个不同的数,存入int[] stock中,并对所用stock的可能性调用fun函数,寻找符合条件的乘数对。
代码实现
import java.util.Arrays;
public class Problem2 {
//当数字abcd存储在a[4]中时,a0~3分别是d,c,b,a;
private static int[] number = new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};//存储0~9,用于问题二的探讨四个其他互异数字
private static int[] stock = new int[]{2, 3, 5, 7};//构成的要求数字的基本元素
private static int[] merge = new int[5];//用于存储两个因数合并,前三位为a后2位为b
private static void show(int[] a) {
for (int i = a.length - 1; i >= 0; i--) {
if (a[i] < 0 || a[i] > 9) {
throw new IllegalArgumentException("数组的数字应该在0~9之间");
}//进行参数的合法性校验
System.out.print(a[i]);
}
System.out.println("");
}//将存储在数组里的数以数值的形式打印出来
private static boolean isProper(int x) {//单个数值是否符合条件
if (x >= 10 || x < 0) {
throw new IllegalArgumentException("请传入十以内的自然数");
} else return x == stock[0] || x == stock[1] || x == stock[2] || x == stock[3];
}
private static boolean isProper(int[] a, int[] b) {//计算指定a2a1a0×b1b0,判断是否符合条件
if (a.length != 3 || b.length != 2) {//检查参数的合法性
throw new IllegalArgumentException("数组a应为3位,数组b应为2位");
}
for (int x : a) {
if (!isProper(x)) {
return false;
}
}
for (int x : b) {
if (!isProper(x)) {
return false;
}
}
int[] m = new int[4];
int[] n = new int[4];//用于存储计算过程中的第一行和第二行
int[] result = new int[5];//用于存储结果
int k = 0;//用于存储计算过程中的进位
boolean[] check = new boolean[10];//check[2],check[3],check[5],ckeck[7]分别用于记录2357是否出现过
for (int i = 0; i <= 2; i++) {//进行第一行m[4]的计算
m[i] = (b[0] * a[i] + k) % 10;
if (!isProper(m[i])) {
return false;
} else {
check[m[i]] = true;
}//过程中发现不符合条件则返回false
k = (b[0] * a[i] + k) / 10;
}
m[3] = k;
if (!isProper(m[3])) {
return false;
} else {
check[m[3]] = true;
}//过程中发现不符合条件则返回false
k = 0;
for (int i = 0; i <= 2; i++) {//进行第二行n[4]的计算
n[i] = (b[1] * a[i] + k) % 10;
if (!isProper(n[i])) {
return false;
} else {
check[n[i]] = true;
}//过程中发现不符合条件则返回false
k = (b[1] * a[i] + k) / 10;
}
n[3] = k;
if (!isProper(n[3])) {
return false;
} else {
check[n[3]] = true;
}//过程中发现不符合条件则返回false
k = 0;
result[0] = m[0];//对result[5]进行计算
for (int i = 1; i <= 3; i++) {
result[i] = (m[i] + n[i - 1] + k) % 10;
if (!isProper(result[i])) {
return false;
} else {
check[result[i]] = true;
}//过程中发现不符合条件则返回false
k = (m[i] + n[i - 1] + k) / 10;
}
result[4] = k + n[3];
if (!isProper(result[4])) {
return false;
} else {
check[result[4]] = true;
}//过程中发现不符合条件则返回false
return check[stock[0]] && check[stock[1]] && check[stock[2]] && check[stock[3]];
}
private static void fun(int k) {//采用深度优先算法,将stock中的数字分配到两个乘数中,并进行判断;k表示merge[k]及之后的未分配到数字
if (k == 5) {//当merge中全部得到分配后,拆分merge并进行判断
if (isProper(Arrays.copyOfRange(merge, 0, 3), Arrays.copyOfRange(merge, 3, 5))) {
show(Arrays.copyOfRange(merge, 0, 3));
show(Arrays.copyOfRange(merge, 3, 5));
System.out.println("");
}//如果拆分后的因数符合条件,打印该因式
return;
}
for (int x : stock) {//merge第k位待分配时,依次分给merge第k位stock的所有值,并进行递归分配第k+1位
merge[k] = x;
fun(k + 1);
}
}
private static void fun2(int j, int k) {
//j表示number中的number[j]及以后没有决定是否选择,k表示已经在number中选择了k个不同的数字放到了stock中
if (k == 4) {//当已经选择足够的4个不重复数字放入stock中,执行fun函数
fun(0);
} else if (j == 10) {//当没有数字可选,且没有选够4个数字时,返回空
return;
} else {//有数字可选,且未选够数字时,对number[j]进行选取,并回溯该步骤,对j+1及之后的数字进行选取
stock[k] = number[j];
fun2(j + 1, k + 1);
fun2(j + 1, k);
}
}
public static void main(String[] args) {
fun(0);//调用此函数,寻找2357的乘数
// fun2(0, 0);//调用此函数,寻找包括0的四个不相同数字满足要求的乘数
// fun2(1, 0);//调用此函数,寻找不包括0的四个不相同数字满足要求的乘数
}
}
运行结果