- 题目:
如果一个n位数包含了1至n的所有数字恰好一次,我们称它为全数字。
例如:
1)五位数15234就是一个1至5全数字。
2)7254是一个特殊的乘积,因为在等式39 x 186 = 7254 中,被乘数、乘数和乘积恰好是1至9全数字。
找出所有被乘数、乘数和乘积恰好是1至9全数字的乘法等式,并求出这些等式中乘积的和。
注:有些乘积可能从多个乘法等式中等到,但在求和的时候只计算一次。
- 题目分析:
通过题目描述,我们可以得到如下信息:
1)这是一道枚举类型的题目,枚举 a * b = c, 并判断a ,b,c是否符合题目要求;
2)a < b (这个条件,是我们根据题得出的,a 和 b 必然一个大一下小)
3) a、b、c 的位数分别是多少?这个问题是有一个限制条件的,就是 a、b和c的总位数是9.
那么,假设a是一位数,b 就不可能是一位数,因为a *b =c 必然会小于9 位数,不满足题意,我们把思路过程以表格的形式展现出来:
a | b | a*b = c | 9位数 |
1位数 | 1位数 | 小于3位数 | 不满足 |
1位数 | 2位数 | 小于4位数 | 不满足 |
1位数 | 3位数 | 小于5位数 | 不满足 |
1位数 | 4位数 | 4位或5位 | 满足 |
1位数 | 5位数 | 5位或6位 | 不满足 |
2位数 | 2位数 | 小于5位 | 不满足 |
2位数 | 3位数 | 4位或5位 | 满足 |
2位数 | 4位数 | 大于3位数 | 不满足 |
3位数 | 3位数 | 大于3位数 | 不满足 |
因为我们已经 设定 了 a < b 这个前提条件,所以,根据表格所示,a最大只能是 两位数,而b 最大可能是4位数。
4) 为了满足 a的位数 + b的位数 + c的位数 = 9, 我们就要知道如何计算一个数的位数。
a 的位数 就是 +1 , 即log 以10 为底,下取整,a的对数再加1
所以 a,b,c 总位数为:digits = + 1 + 1 + + 1
这里是以10 为底,是因为题意说明是10进制,我们可以得出一个一般结论:
求一个正整数n在m进制下的数字位数,采用如下公式: g(n) = +1
- 代码实现
#include <stdio.h>
#include <math.h>
#define MAX_N 100000
//用于存放c值( c = a*b)
int keep[MAX_N+5] = {0};
//计算整数n的位数
int digit(int n){
return floor(log10(n) +1;
}
// 判断整数a,b,c 是否为全位数, 如果是,返回1,否则,返回0;
int is_val(int a, int b, int c){
if(digit(a) + digit(b) + digit(c) - 9 != 0) return 0;
int num[10] = {0};
num[0] = 1;
int flag = 1;
flag = flag && add_to_arr(num, a);
flag = flag && add_to_arr(num, b);
flag = falg && add_to_arr(num, c)
return flag;
}
int main(){
int sum = 0;
for(int a = 1; a < 100; a++){
for(int b = a+1; b < 10000;b++){
int c = a * b;
if(!is_val(a,b,c)) continue; //如果a,b,c不满足全位数,则执行continue
if(keep[c]) continue; //如果计算出的c值已经存在,则continue,确保一个c只出现一次;
sum += a*b;
keep[c] = 1;
printf("%d * %d = %d\n", a,b,c);
}
}
printf("sum = %d\n", sum);
return 0;
}
- 运行结果:
- 代码分析:
这段代码也主要是在训练我们的编码能力。
我们要理解:
1. keep数组的作用,是为了呼应题目描述中的“有些乘积可能从多个乘法等式中等到,但在求和的时候只计算一次” 这个条件,即一个c值只能出现一次。
2. a,b ,c 以及MAX_N 的最大值是如果估算出的