21位花朵数 C语言(执行时间小于16s)

一个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分钟内运行完毕。

#include<stdio.h>
#include <string.h>
#define N 100000//虚拟进制
#define BN 5//exp21的容量需求
int exp21[10][BN]={//0-9的21次方
{00000,00000,00000,00000,00000},
{00000,00000,00000,00000, 1},
{00000,00000,00000, 20,97152},
{00000,00000, 1, 4603,53203},
{00000,00000, 439,80465,11104},
{00000,00000,47683,71582, 3125},
{00000, 21,93695, 6403,77856},
{00000, 558,54586,40832,84007},
{00000, 9223,37203,68547,75808},
{00001, 9418,98913,15123,59209}
};
int cm[10];//0-9被选的次数
int nm[10];//21位数中0-9出现的次数
int sum[BN];//累加和
int pass[1000][10];//已经出现过的
int sum_pass;
int check()//检查sum是否合法
{
if (sum[0]>9&&cm[0]!=21) return 0;
return 1;
}
void Add(int *a,int *b)//大数加法:a+=b
{
int i,carry=0;
for (i=BN-1;i>=0;i--)
{
a[i]=a[i]+b[i]+carry;
carry = 0;
if (a[i]>=N)
{
a[i]-=N;
carry = 1;
}
}
}
void Sub(int *a,int *b)//大数减法:a-=b
{
int i,borrow=0;
for (i=BN-1;i>=0;i--)
{
a[i]=a[i]-b[i]+borrow;
borrow = 0;
if (a[i]<0)
{
a[i]+=N;
borrow = -1;
}
}

}
int IsRight()//判断是否是花朵数
{
int i,j;
memset(nm,0,sizeof(nm));
for (i=0;i<BN;i++)//统计sum中0-9的个数
{
j=sum[i];
while (j)
{
nm[j%10]++;
j/=10;
}
}
for (i=0;i<10;i++)
if (cm[i]!=nm[i])
return 0;
return 1;
}
void save()//将花朵数存储在pass数组中
{
int i;
pass[sum_pass][0]=sum[0];
for (i=1;i<BN;i++)
pass[sum_pass][i]=sum[i];
sum_pass++;
}
void sln(int n,int m)//用若干个m填充n个空
{
int i,j;
if (n==0)
return;
if (m==0)
{
cm[0]+=n;
if(IsRight())
save();
cm[0]-=n;
return;
}
for (i=n;i>=0;i--)//最多用n个,最少用0个
{
cm[m]+=i;
for (j=0;j<i;j++)Add(sum,exp21[m]);//sum加上i个exp21[m]
if (!check())//检查是否溢出
{
cm[m]-=i;
for (j=0;j<i;j++)Sub(sum,exp21[m]);//sum减去i个exp21[m]
continue;
}
if(n==1&&IsRight()) save();
sln(n-i,m-1);//用若干m-1填补剩余的n-i个空
cm[m]-=i;
for (j=0;j<i;j++)Sub(sum,exp21[m]);//sum减去i个exp21[m]
}
}
void print()//输出结果、有点偷懒。。。
{
printf("%d%05d%05d%05d%05d\n",pass[1][0],pass[1][1],pass[1][2],pass[1][3],pass[1][4]);
printf("%d%05d%05d%05d%05d\n",pass[0][0],pass[0][1],pass[0][2],pass[0][3],pass[0][4]);
}
void main()
{
sln(21,9);
print();
}
字节跳动内推

找我内推: 字节跳动各种岗位
作者: ZH奶酪(张贺)
邮箱: cheesezh@qq.com
出处: http://www.cnblogs.com/CheeseZH/
* 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

原文地址:https://www.cnblogs.com/CheeseZH/p/2434560.html