求21位水仙花数(C语言实现)

/*
 * 21位水仙花数
 */

#include<stdio.h>
#include<string.h>
#include<time.h>

#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<k;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<k-1;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<k;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<DIGIT;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);
}

 

展开阅读全文

没有更多推荐了,返回首页