一个N位的十进制正整数,如果它的每个位上的数字的N次方的和等于这个数本身,则称其为花朵数。
例如:
当N=3时,153就满足条件,因为 1^3 + 5^3 + 3^3 = 153,这样的数字也被称为水仙花数(其中,“^”表示乘方,5^3表示5的3次方,也就是立方)。
当N=4时,1634满足条件,因为 1^4 + 6^4 + 3^4 + 4^4 = 1634。
当N=5时,92727满足条件。
实际上,对N的每个取值,可能有多个数字满足条件。
程序的任务是:求N=21时,所有满足条件的花朵数。注意:这个整数有21位,它的各个位数字的21次方之和正好等于这个数本身。
解题思路:花朵数为21位数,肯定不是int/long所能表示的范围,所以本题使用大整数来表示。
那么有的同学可能想到了使用for循环遍历100…000~999…999这么多的21位数进行暴力破解,但是这个计算量是非常巨大的,计算机无法处理,那么我们应该怎么寻找其中符合条件的数呢?
有的同学可能想到了,21位数当中一定有许多重复的累加和。到这里也就不难想了,决定21位数字幂累加的和并不取决于数字的顺序,而是每个数字出现的次数。·
现在我们只需要对这个次数进行遍历就行了,这样我们的计算量就大大缩小了。
我们设置一个存放每个数字出现次数的数组,对它进行遍历,枚举21位数字的出所有可能。对每个可能都做计算,判断它是否为一个21位数,这个21位数中每个数字出现的个数是否与我们的数组一致。这样我们就可以得到这个21位花朵数了。
首先我们看一下大整数的方法:
vauleOf(int) 将整型数据转换为大数据
multiply() 大数据乘法
add() 大数据加法
.ZERO/.ONE 大数据0、1的定义
最后的计算结果比较:由于记录21位数据的方法采用的是一个存储数字出现次数的数组,所以要进行数组的判断。这里的比较方法是将计算的结果化为字符串s,对s中的字符进行解析化为数组,与原数组比较。
import java.math.BigInteger;
public class X11 {
static BigInteger[] x = new BigInteger[10];
public static BigInteger pow_21(int n){
BigInteger b = BigInteger.ONE;
for(int i=0;i<21;i++){
b = b.multiply(BigInteger.valueOf(n));//21次乘以n,得n^21
}
return b;
}
public static void test(int[] a){
BigInteger sum = BigInteger.ZERO;//总和
for(int i=1;i<10;i++){//加9次(0的21次方等于0,不需要加)
sum = sum.add(x[i].multiply(BigInteger.valueOf(a[i])));//valueOf(int) 方法对int进行转换为BigInteger大整数
}
//接下来比较
String s = sum.toString();//大整数,使用字符串进行比较
if(s.length() != 21) return;
int[] a1 = new int[10];//注意是与a[]进行比较,所以需要将大整数的结果字符串进行解析
for(int i=0;i<21;i++){
a1[s.charAt(i) - '0']++;//按位处理结果,转换为a1[] 的数据
}
//比较
for(int i=0;i<10;i++){
if(a1[i] != a[i]) return;
}
System.out.println(s);
}
//x存放数字的21次方数据 , a存放数字出现次数 , cur当前处理的数字 , use已经使用的位数
public static void f(int[] a,int cur,int use){
if(use == 21){
test(a);
return;
}
if(cur==9){//9个数字枚举完毕,进行计算判断
a[9] = 21-use;
test(a);//测试是否成功找到数字
return;
}
//枚举
for(int i=0; i<21-use; i++){
a[cur] = i;//当前数字出现的次数:i
f(a,cur+1,use+i);
a[cur] = 0;//不要忘记回溯
}
}
public static void main(String[] args) {
//0~9的21次方给数组x[]
for(int i=0; i<10; i++){
x[i] = pow_21(i);//pow_21 方法计算21次方
}
int[] a = new int[10];//记录每个数字出现的次数
f(a,0,0);//递归主方法
}
}
//结果
//128468643043731391252
//449177399146038697307