问题描述:在三分钟内求出所有的21位水仙花数
直接上代码:
public class 求21位数的水仙花数 {
/**
* @param args
*/
public static void main(String[] args) {
long startTime=System.currentTimeMillis();//程序开始时间
BigInteger pw[]=new BigInteger[10];
for(int i=0;i<pw.length;i++){
pw[i]=p(i);//每个下标存0~9的21次方
}
int nn[]=new int[10];//统计各个数字的出现次数
f(pw,nn,0,0);
System.out.println("OK");
long endTime=System.currentTimeMillis();//程序结束时间
System.out.println((endTime-startTime)/1000f);
}
private static void f(BigInteger[] pw, int[] nn, int cur, int use) {
if(cur==9){
nn[9]=21-use;//将当前位置的数字的次数减去使用次数
ji_suan(pw,nn);//判断是不是水仙花数,是的话输出
return;
}
//当前位置所有可能枚举
for(int i=0;i<21-use;i++){
/*从第一个位置开始遍历,21-use减少遍历次数,减去已用过的位置如:
第一次大遍历,i=0,use=0时
第一次cur==9时,nn表中数据为:0,0,0,0,0,0,0,0,0,21
每次递归除了第一个0不变,其他位递归,且相加为21,
第二次大遍历,i=1,use=0时
第一次cur==9时,nn表中数据为:1,0,0,0,0,0,0,0,0,20
每次递归除了第一个1不变,其他位递归,且相加为20,21-use(use此时为1)
21-use就是这个意思
*
*/
nn[cur]=i;//0~9出现的次数
f(pw, nn, cur+1, use+i);//pw:每个数字的21次方,nn:每个数字出现的次数,cur:当前数字,use:当前位置数字个数已使用的次数
}
}
private static void ji_suan(BigInteger[] pw, int[] nn) {
BigInteger sum=BigInteger.ZERO;
for(int i=0;i<10;i++){
sum=sum.add(pw[i].multiply(BigInteger.valueOf(nn[i])));
}
String string=""+sum;
if(string.length()!=21)
return;
//确定各数字出现多少次
int[] nn2=new int[10];
for(int i=0;i<21;i++){
nn2[string.charAt(i)-'0']++;
}
for(int i=0;i<10;i++){
if(nn[i]!=nn2[i])
return;
}
System.out.println(string);
}
private static BigInteger p(int i) {
BigInteger base=BigInteger.valueOf(i);
return base.pow(21);
}
}