一个三位整数(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;
}