/*
* 21位水仙花数
*/
#include
#include
#include
#define DIGIT 21
char pow[DIGIT][50]={0};//存储0到9的DIGIT次方
int countNumber[10];//0-9的个数
char powDigit[10][DIGIT+1][DIGIT*3];//存储(0-9的21次方)*(0-9的个数)
char countDigit[][3]={"0","1","2","3","4","5","6","7","8","9","10","11","12",
"13","14","15","16","17","18","19","20","21"};
//大整数加法
void add(char* result,char* a,char* b)
{
int temp[50]={0};
int k=0,j,i;
i=strlen(a)-1,j=strlen(b)-1;
//相加
while(i>=0 && j>=0){
temp[k++]=(a[i--]-'0')+(b[j--]-'0');
}
while(i>=0)
temp[k++]=a[i--]-'0';
while(j>=0)
temp[k++]=b[j--]-'0';
//处理进位,使temp中各个元素的值在0--9之间
for(i=0;i
temp[i+1]+=temp[i]/10;
temp[i]%=10;
}
while(temp[i]>9){
temp[i+1]+=temp[i]/10;
temp[i]%=10;
i++;
}
//把结果存入result字符串中
k=i;
j=0;
for(i=k;i>=0;i--){
if(j==0 && temp[i]==0)
continue;
result[j++]=temp[i]+'0';
}
if(j==0)
result[j++]='0';
result[j]=0;
}
//大整数减法(a>b)
void sub(char* result,char* a,char* b)
{
int temp[50]={0};
int k=0,j,i;
i=strlen(a)-1,j=strlen(b)-1;
//相减
while(i>=0 && j>=0){
temp[k++]=(a[i--]-'0')-(b[j--]-'0');
}
while(i>=0)
temp[k++]=a[i--]-'0';
//使temp中各个元素的值在0--9之间
for(i=0;i
if(temp[i]<0){
temp[i]+=10;
temp[i+1]-=1;
}
}
//把结果存入result字符串中
k=i;
j=0;
for(i=k;i>=0;i--){
if(j==0 && temp[i]==0)
continue;
result[j++]=temp[i]+'0';
}
if(j==0)
result[j++]='0';
result[j]=0;
}
//大整数乘法
void multiply(char* result,char* a,char* b)
{
int temp[50]={0};
int k=0,j,i;
int len1=strlen(a),len2=strlen(b);
//相乘
for(i=len1-1;i>=0;i--){
k=len1-1-i;
for(j=len2-1;j>=0;j--){
temp[k++]+=(a[i]-'0')*(b[j]-'0');
}
}
//处理进位,使temp中各个元素的值在0--9之间
for(i=0;i
temp[i+1]+=temp[i]/10;
temp[i]%=10;
}
while(temp[i]>9){
temp[i+1]+=temp[i]/10;
temp[i]%=10;
i++;
}
//把结果存入result字符串中
k=i;
j=0;
for(i=k;i>=0;i--){
if(j==0 && temp[i]==0)
continue;
result[j++]=temp[i]+'0';
}
if(j==0)
result[j++]='0';
result[j]=0;
}
//给pow数组赋值,计算出0到9的DIGIT次方
void init()
{
int i,j;
strcpy(pow[0],"0");
strcpy(pow[1],"1");
for(i=2;i<=9;i++){
pow[i][0]='1';
for(j=1;j<=DIGIT;j++)
multiply(pow[i],pow[i],countDigit[i]);
}
for(i=0;i<10;i++)
for(j=0;j<=DIGIT;j++)
multiply(powDigit[i][j],pow[i],countDigit[j]);
}
//判断是否是水仙花数
int judge()
{
int i,temp;
static char sum[50]={'0',0};//保存上一次的结果
int tempCountNum[10]={0};
static int laseNum[10]={0};//保存上一次的各个数字的个数
for(i=1;i<10;i++){
if((temp=countNumber[i]-laseNum[i])<0){
sub(sum,sum,powDigit[i][-temp]);
laseNum[i]+=temp;
}
else if(temp>0){
add(sum,sum,powDigit[i][temp]);
laseNum[i]+=temp;
}
}
for(i=0;i
switch(sum[i]){
case '0':tempCountNum[0]+=1;break;
case '1':tempCountNum[1]+=1;break;
case '2':tempCountNum[2]+=1;break;
case '3':tempCountNum[3]+=1;break;
case '4':tempCountNum[4]+=1;break;
case '5':tempCountNum[5]+=1;break;
case '6':tempCountNum[6]+=1;break;
case '7':tempCountNum[7]+=1;break;
case '8':tempCountNum[8]+=1;break;
case '9':tempCountNum[9]+=1;break;
}
for(i=0;i<10;i++)
if(countNumber[i]!=tempCountNum[i])
return 0;
puts(sum);
return 1;
}
//寻找DIGIT位水仙花数
void findNumber(int n,int count)
{
int i,max=DIGIT;
int start=0;
if(n==0){
countNumber[0]=DIGIT-count;
judge();
return;
}
switch(n){
case 9:max=9;break;
case 8:max=21;break;
default:max=20;break;
}
for(i=max;i>=start;i--){
countNumber[n]=i;
if(count+i>DIGIT)
continue;
if(countNumber[9]==0 && countNumber[8]<10)
return;
findNumber(n-1,count+i);
}
}
void main()
{
int start=clock();
init();
printf("21位水仙花数有:\n");
findNumber(9,0);
printf("用时:%d ms\n",clock()-start);
}