关于水仙花数及拓展

一个三位整数(100~999),若各位数的立方和等于该数自身,则称其为“水仙花数”(如:153=13+53+33),找出所有的这种数。

 现在对问题进行拓展,有n位的水仙花数,现在要求给定输入n,求出n位的所有水仙花数

#include<stdio.h>
#include<math.h>
int main()
{
	int n;
	scanf("%d",&n);
	int b=pow(10,n)-1;        //表示范围
	int a=pow(10,n-1);         
	
	int i;
	for(i=a;i<=b;i++)        //枚举区间的每一个数
	{
		int sum=0;
		int q=i;            //记录
		while(q!=0)
		{
			sum+=pow(q%10,n);
			q/=10;
		}                    //sum为该列举数字的每个位置的数字n方和
		if(i==sum)            //如果之和等于该数,输出
		{
			printf("%d\n",i);
		}
	}
	return 0;

}

这个算法的运行时间随着位数的增加呈现指数级的增长,现在对其算法进行优化

由于0-9每个数字的n方总是固定的,故其实只要运算一次就好,这里采用打表

#include<stdio.h>
#include<math.h>
int table[10];    //table为打表数组
int main()
{
	int n;
	scanf("%d",&n);
	int b=pow(10,n)-1;
	int a=pow(10,n-1);
	
	int i;
	for(i=0;i<10;i++)
	{
		table[i]=pow(i,n); //制表
	}
	for(i=a;i<=b;i++)
	{
		int sum=0;
		int q=i;
		while(q!=0)
		{
			sum+=table[q%10]; //引用表运算
			q/=10;
		}
		if(i==sum)
		{
			printf("%d\n",i);
		}
	}
	return 0;

}

但是这个算法还是不够高效,现在寻求更高效的算法

我们现在先看看水仙花数的本质:一个n位数,每个数字的n方和等于该数,

那么可以看出,之前的算法之所以效率较低,其中重要的原因是 先前的算法采用的是暴力枚举的思路,而这里如果抽出水仙花的本质,就是对一个n位数的运算,完全可以看出n个数字,这种看法可以大大简化计算量

简化思路:比如一个三位数,他的总共的数字取法只有220种,其中有一种取法是 一个1 一个5

一个3 (顺序不关心) 然后计算次方和 得到一个原数,倘若这个原数真的出现了一个1 一个5 一个3    那么这个原数就是水仙花数(逆推)

数字取法的代码:

#include<stdio.h>
#include<string.h>
#include<ctype.h>
int main()
{
	int t[10]={0};
	int i;
	int cnt=0;
	int n;
	scanf("%d",&n);
	for(t[0]=0;t[0]<=n;t[0]++)
	{
		for(t[1]=0;t[1]<=n-t[0];t[1]++)
		{
			for(t[2]=0;t[2]<=n-t[0]-t[1];t[2]++)
			{
				for(t[3]=0;t[3]<=n-t[0]-t[1]-t[2];t[3]++)
				{
					for(t[4]=0;t[4]<=n-t[0]-t[1]-t[2]-t[3];t[4]++)
					{
						for(t[5]=0;t[5]<=n-t[0]-t[1]-t[2]-t[3]-t[4];t[5]++)
						{
							for(t[6]=0;t[6]<=n-t[0]-t[1]-t[2]-t[3]-t[4]-t[5];t[6]++)
							{
								for(t[7]=0;t[7]<=n-t[0]-t[1]-t[2]-t[3]-t[4]-t[5]-t[6];t[7]++)
								{
									for(t[8]=0;t[8]<=n-t[0]-t[1]-t[2]-t[3]-t[4]-t[5]-t[6]-t[7];t[8]++)
									{
										t[9]<=n-t[0]-t[1]-t[2]-t[3]-t[4]-t[5]-t[6]-t[7]-t[8];
										cnt++;
									}
								}
							}	
						}
					}
				}
			}
		}
	}
	printf("%d",cnt);
	return 0;
}
    

借鉴别人思路后,可以转化为递归解决

如下:

#include<stdio.h>
int cnt=0;
void search(int t[],int i,int left)
{
	int n;
	if(i==9)     //递归到第九层时退出
	{
		t[i]=left;
		cnt++;
		return ;
	}
	for(n=0;n<=left;n++)
	{
		t[i]=n;
		search(t,i+1,left-n);
	}
}
int main()
{
	int t[10]={0};
	int i=0;
	int n;
	scanf("%d",&n);
	search(t,0,n);
	printf("%d",cnt);
	return 0;
}
    

代码:

#include<stdio.h>
#include<math.h>
int cnt=0;
void search(int t[],int i,int left);
int judge(int sum,int t[10]);
int table[10]={0};

int main()
{
	int i;
	int n;
	int t[10];
	scanf("%d",&n);
	for(i=0;i<10;i++)
	{
		table[i]=pow(i,n);
	}
	search(t,0,n);

}
void search(int t[],int i,int left)
{
	int sum=0;
	int n;
	if(i==9)     //递归到第九层时退出
	{
		t[i]=left;
		for(int j=0;j<10;j++)
		{
			sum+=t[j]*table[j];
		}
		if(judge(sum,t))            //judge用来判断sum中是否出现了对应数次数
			{
				printf("%d\n",sum);
			}
		return;
	}
	for(n=0;n<=left;n++)
	{
		t[i]=n;
		search(t,i+1,left-n);
	}
}

int judge(int sum,int t[])
{
	int temp[10]={0};
	while(sum)
	{
		temp[sum%10]++;
		sum/=10;
	}
	for(int i=0;i<10;i++)
	{
		if(temp[i]!=t[i])
		{
			return 0;
		}
	}
	return 1;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值