求21位所有满足条件的花朵数。

花朵数

一个N位的十进制正整数,如果它的每个位上的数字的N次方的和等于这个数本身,则称其为花朵数。

例如:

N=3时,153就满足条件,因为 1^3 + 5^3 + 3^3 = 153,这样的数字也被称为水仙花数(其中,“^”表示乘方,5^3表示53次方,也就是立方)。

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 ;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值