1 题目
花朵数
一个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次方之和正好等于这个数本身。
如果满足条件的数字不只有一个,请从小到大输出所有符合条件的数字,每个数字占一行。因为这个数字很大,请注意解法时间上的可行性。要求程序在3分钟内运行完毕。(这是蓝桥杯的比赛题,解法有很多种,我的解法是对http://www.lanqiao.org/webHomePage.action?detailArticlePage&articleId=364&catalogId=10&itemId=27 他们官方发布的视频的总结及自己的理解,对不爱看视屏的你或许有帮助)
参考结果:
128468643043731391252
449177399146038697307
2 解题思路
1.怎么表示结果?结果是一个21位的数字如果我们用int 和long 的话都是不能表示的。那我们要用BigInteger.应为它并没有语法长度限制,仅仅受限于机器的内存。
2.怎么处理算法?我们很容易想到遍历100000000000000000000----999999999999999999999
但是这样确实不行的。不要认为机器足够快就能就能计算出来。目前的微机硬件水平是不能出结果的。
不能每个数字去遍历,那么我们转换为21个位置0-9 每个数字出现的次数进行大排列。
例:
449177399146038697307 和 730744917739914603869
他们的21次方的和都是一样,这样我们就不用去管他们每个数字出现的位置。而转化对0-9 每个数字出现的次数进行排列。具体的一些小的技巧在程序中会体现出来
3 具体的代码
import java.math.BigInteger; public class FlowerNum { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub long time=System.currentTimeMillis();//计时 int n=21; BigInteger[] big=new BigInteger[10];//0-9的21次方 for(int i=0;i<10;i++){ // big[i]=BigInteger.valueOf(i).pow(n); big[i]=p(i); System.out.print(big[i]+"\r\n"); } int[] nu =new int[10]; //算法核心:21个位置0-9 每个数字出现的次数进行大排列。 f(big,nu,0,0); time=System.currentTimeMillis()-time; System.out.print(time/1000+"s");//输出计算时间噎死一个程序结束的信号 } //求次方 private static BigInteger p(int i) { // TODO Auto-generated method stub //求21次方 BigInteger big=BigInteger.ONE; for(int i1=0;i1<21;i1++) { big=big.multiply(BigInteger.valueOf(i)); } return big; } //cur 是代表当前处理 nu 的第几位 // use 是代表占用了多少位 private static void f(BigInteger[] big, int[] nu, int cur, int use) { // TODO Auto-generated method stub //到了最后一位 。递归结束 if(cur==9) { nu[9]=21-use; ji_suan(big,nu); return; } //对当前位置的所有肯呢过进行枚举 for(int i=0 ;i<=21-use;i++) { nu[cur]=i; f(big ,nu,cur+1,use+i); } } private static void ji_suan(BigInteger[] big, int[] nu) { // TODO Auto-generated method stub //求和 BigInteger big2=BigInteger.ZERO; for(int i=0;i<=9;i++) big2=big2.add(big[i].multiply(BigInteger.valueOf(nu[i])));//big[i]的出现次数和值的乘积的累加 //把结果放到s这个字符串中 String s=""+big2; //结果不足21位直接pass if (s.length()!=21)return; //确定每个数字出现的次数 int[] nn2=new int[10]; //搜寻在s中0-9出现的次数并存放在nn2 数组中 for(int i=0 ;i<21;i++ ) nn2[s.charAt(i)-'0']++;//nn2[i]++; for(int i=0 ; i<=9;i++) //比较出现的次数是不是相等 { if(nu[i]!=nn2[i]) return; } System.out.print(s); } }
4 总结
本程序的解题过程就是:
定义—>计算0-9 的21次方-->枚举21个位置0-9出现的次数-->计算21个位置元素21次方的和-->比较和与原数的0-9出现次数比较-->输出