花朵数
一个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分钟内运行完毕。
本人使用的 Intel(R) Core(TM) i5 CPU M460 2.53GHz 32位的系统执行了50s 这个程序还有优化的可能了,不知道大家有没有别的方法呀?
主要思路:比如 123456712345671234567 和 234567123456712345671 和 345671234567123456712 如果采用遍历的话,这几个数字都需要计算的,我们可以发现虽然这几个
数是不同的,0-9每一个数出现的次数是一样的,我们要做很多次没有意义的运算,为什么哪?是因为在结算这几个数的花朵数的时候,他们的结果是一样,所以我没有
采用遍历的方法,而是让每次确定0-9每次出现的个数就行了,这样就可以将计算的次数减少了很多,如果遍历需要10^21,而采用此种方法需使用21^10/2还要少的,
光这样还是不行,根据结果结果应该是分布在0-9^21*21之间的,这些书只有21位的数才又用,其他的都是没有用的,我从最大数开始判断,当结果位数小于21位时候结束
判断了,只有在是21位的时候,计算1-9出现了多少次?如果和计算使用的1-9次数一样的时候这个数是花朵数输出呀。
#include <stdio.h>
#include <string.h>
#include<stdlib.h>
#include <time.h>
#define MAX 255
#define LEN 30
int Pow(unsigned char result[],int num,int power)
{
char loc,temp,jw=1;
int i;
result[LEN-2] = num ;
for(int j = 0;j<power-1;j++)
{
loc = LEN - 2 ;
temp = 0 ;
i=0;
while(i<jw)
{
result[loc] = result[loc]*num +temp ;
temp = result[loc]/10;
if(temp) result[loc] = result[loc] - temp*10 ;
loc --;
i++;
}
if(temp)
{
result[loc] = temp ;
jw ++;
}
}
return 0 ;
}
int Mulit(unsigned char result[],unsigned char mulits[],int num)
{
int loc = LEN -2;
int temp = 0;
while(0 <= loc)
{
result[loc] = mulits[loc]*num +temp ;
temp = result[loc]/10;
if(temp) result[loc] = result[loc] - temp*10 ;
loc -- ;
}
while(temp)
{
result[loc] = temp %10;
temp = temp /10 ;
loc --;
}
while(loc >=0)
{
result[loc] =0;
}
return 0 ;
}
int Add (unsigned char result[],unsigned char addstr[])
{
int loc = LEN -2;
int temp = 0;
while(0 <= loc)
{
result[loc] = result[loc]+addstr[loc] +temp ;
temp = result[loc]/10;
if(temp) result[loc] = result[loc] - temp*10 ;
loc -- ;
}
if(temp )result[loc] = temp;
return 0 ;
}
int Plus (unsigned char result[],unsigned char plus[])
{
int loc = LEN -2;
int temp = 0;
while(0 <= loc )
{
result[loc] = result[loc]-plus[loc] +10 +temp;
temp = result[loc]/10;
if(temp) {temp = 0;result[loc] = result[loc]%10;}
else
{temp = -1;};
loc -- ;
}
return 0 ;
}
int Get_LEN(unsigned char *result)
{
int len =0;
int loc = 0 ;
while(loc < LEN-1)
{
if(!result[loc])
loc ++;
else
{
len = LEN -loc-1 ;break;
}
}
return len ;
}
int main()
{
unsigned char jc[10][LEN]={0}; //存储0-9的21幂
char num[22] ={0}; //存储要求数字的最大值
char gs[10]={0} ; //当前要求的数字中0-9出现的次数
char reslutgs[10]={0};//结果出现数字中0-9出现的次数
unsigned char result[LEN]={0};
unsigned char tempresult[LEN] ={0};
char geshu = 0 ; //还有多少个数字没有使用
int chlen=0;
int nowNum = 9 ;
int i = 0 ;
double time ;
char bl = 0 ;
clock_t begin,end;
begin = clock();
//求0-9的21幂
jc[0][LEN-2]=0;
jc[1][LEN-2]=1;
for(i =2;i<10;i++ )
{
Pow(jc[i],i,21);
}
gs[9] = 21;
Mulit(result,jc[9],21);
nowNum = 0 ;
while(-1 != gs[9])
{
chlen = Get_LEN(result);
geshu =gs[nowNum];
bl=0;
while(!gs[nowNum] || !nowNum)
{
nowNum++;
bl= 1;
}
if(21>chlen)break;
if(21==chlen)
{
for(i=0;i<10;i++)
{
reslutgs[i]=0;
}
for(i=8;i<29;i++)
{
reslutgs[result[i]]++;
}
for(i=1;i<10;i++)
{
if(reslutgs[i]!=gs[i])
{
break ;
}
}
if(10==i)
{
for(i=8;i<29;i++)
{
printf("%c",result[i]+'0');
}
printf("\n");
}
}
gs[nowNum] -- ;
if(bl)
geshu ++;
else
geshu = 1;
nowNum --;
gs[nowNum] =geshu;
geshu =0 ;
for(i=0;i<LEN-1;i++)result[i] = 0;
for(i=1;i<10;i++)
{
if(gs[i])
{
Mulit(tempresult,jc[i],gs[i]);
Add(result,tempresult);
}
}
}
end =clock();
time =(end - begin)/1000;
printf("used %.6lf s\n",time);
scanf("%d",&i);
return 0 ;
}