花朵数_蓝桥杯题目

一个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

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值