一:问题
标题:9数算式
观察如下的算式:
9213 x 85674 = 789314562
左边的乘数和被乘数正好用到了1~9的所有数字,每个1次。
而乘积恰好也是用到了1~9的所有数字,并且每个1次。
请你借助计算机的强大计算能力,找出满足如上要求的9数算式一共有多少个?
注意:
总数目包含题目给出的那个示例。
乘数和被乘数交换后作为同一方案来看待。
二:分析
需要找出符合要求的算式,首先需要找到所有满足9数算式要求的乘数被乘数字符串(要求可以描述为:①字符串分割为乘数和被乘数后用到了1-9各一次②乘积也用到了1-9各一次)。
找字符串的过程类似于深度优先搜索的思想,最终的目标是使字符串长度达到9且用到了1-9各一次。每次搜索不找到一条完整的“路径”就不停下来。可以定义一个状态数组来记录1-9数字的使用情况,在dfs的过程中,每次访问到一个数之后,将其标记为true,“使用”完毕后再将其状态改回为false。
dfs过程(引用自@柏枫杨柳)
边界状态:字符串长度达到9
void dfs(String 当前状态)
{
if(当前状态为边界状态)
{
检查字符串是否符合要求
return;
}
for(i=0;i<n;i++) //横向遍历解答树所有子节点
{
//扩展出一个子状态。
修改了全局变量
if(子状态满足约束条件)
{
dfs(子状态)
}
恢复全局变量 //回溯部分
}
}
三:代码
package 一七年真题9数算式;
public class Main {
private static boolean isVisited[] = new boolean[10];
private static int count = 0;
public static void main(String[] args){
String numString="";
long t=System.currentTimeMillis();
dfs(numString,0);
System.out.println(count/2+"\n"+(System.currentTimeMillis()-t)+"ms"); //乘数与被乘数交换视为同一算式
}
private static void dfs(String s,int length)
{
if(length==9)
{
for(int i=1;i<9;i++)
{
int multiplier=Integer.parseInt(s.substring(0, i));
int multiplicand=Integer.parseInt(s.substring(i,9));
int answer = multiplier*multiplicand;
if(check(answer))
{
count++;
//System.out.println(multiplier+"×"+multiplicand+"="+answer);
}
}
return;
}
for(int i=1;i<10;i++)
{
if(isVisited[i]==false)
{
isVisited[i]=true;
dfs(s+i,length+1);
isVisited[i]=false;
}
}
}
private static boolean check(int resultNum)
{
boolean isVisitedC[] = new boolean[10];
while(resultNum!=0)
{
int numNow=resultNum%10;
if(numNow<1&&numNow>9)
return false;
isVisitedC[numNow]=true;
resultNum/=10;
}
for(int i=1;i<10;i++)
{
if(isVisitedC[i]==false)
return false;
}
return true;
}
}