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奶酪博客园博客,原文链接:http://www.cnblogs.com/CheeseZH/archive/2012/04/06/2434560.html,如需转载请自行联系原作者

相关文章
|
1月前
|
存储 C语言
通俗易懂的学习C语言中输入一组数并找出其最大值
通俗易懂的学习C语言中输入一组数并找出其最大值
|
5月前
|
算法 搜索推荐 程序员
C语言第三练——编程实现三个数的平均值
C语言第三练——编程实现三个数的平均值
129 0
|
5月前
|
算法 搜索推荐 程序员
C语言第十练——实现求一个数的所有因数
C语言第十练——实现求一个数的所有因数
110 0
|
10天前
|
C语言
【C语言】用三种循环语句 计算1到1000之间能被2或3整除的数的总和
【C语言】用三种循环语句 计算1到1000之间能被2或3整除的数的总和
|
5月前
|
算法 搜索推荐 程序员
C语言第二练——求三个数的最大值
C语言第二练——求三个数的最大值
138 0
|
6月前
|
C语言
C语言之输出一个数的所有因子之积
C语言之输出一个数的所有因子之积
|
3月前
|
Python
简单计算器实现,包括两个数
简单计算器实现,包括两个数
|
8月前
|
C语言
【C语言初学必看】水仙花数、变种水仙花数背后的知识
【C语言初学必看】水仙花数、变种水仙花数背后的知识
|
9月前
|
机器学习/深度学习 C语言
C语言:给定两个数,求这两个数的最大公约数(新思路:辗转相除法)
思路一:普通方法 总体思路: (一). 生成相关变量; 从键盘输入两个数;
C语言:给定两个数,求这两个数的最大公约数(新思路:辗转相除法)
【C语言】(错题整理) 寻找完数、字符串中各类字符数的统计、最大公约数和最小公倍数、回文数计算 (循环、函数相关内容)
本篇博客旨在整理最近在头歌遇到的难题、错题,对其进行分析并整理。 一、循环 1.寻找完数(计算因子例题) 一个数如果恰好等于它的因子之和,这个数就称为"完数"。 例如,6的因子为1、2、3,而6=1+2+3,因此6是"完数"。 编程序找出1000之内的所有完数。 这道题的首要任务就是找到各个数的因子,然后再对其进行判断。那么计算这个数的因子,我们可以用循环,试每个小于它的数对其进行求余%,结果为零即是因子。