N=21时水仙花数
这题目我一开始考虑的很烦,不知道如何保存这21位数,用数组,那有怎么计算阶乘呢,那我们考虑如果能把21个数分成三个部分,这样一个部分的数超过就进位
所以我写了一个计算阶乘的函数
void fang(int x)
{
long int a = 0,b = 0,c = 1;
for(int i = N;i > 0; --i)
{
c = c * x; //1-7位的数
a = a * x; //8-15位的数
b = b * x; //16-21位的数
while(b > 9999999) //第15的数>10;则需进位到第16位
{
b -= 10000000;
a += 1;
}
while(c > 9999999) //第7的数>10;则需进位到第8位
{
c -= 10000000;
b += 1;
while(b > 9999999) //再次判断第15位是否超过10
{
b -= 10000000;
a += 1;
}
}
}
int d;
int e = N - 14;
while(a) //将16-21位的数依次存到数组arr[x][15]-arr[x][20]
{
d = a % 10;
arr[x][N - (e--)] = d;
a = a / 10;
}
e = N - 7;
while(b) //将8-15位的数依次存到数组arr[x][7]-arr[x][14]
{
d = b % 10;
arr[x][N - (e--)] = d;
b = b / 10;
}
e = N; //将1-7位的数依次存到数组arr[x][0]-arr[x][6]
while(c)
{
d = c % 10;
arr[x][N - (e--)] = d;
c = c / 10;
}
}
最关键的解决了,那我怎么来比较与原来数字是否相等,这是再次出现的问题,所以我一开始天真的想把所有阶乘加起来再比较形成的数,那太烦了,也感觉太low,直接考虑把阶乘求出来的和计算位数,看是否有21位,那这就是我们要的数。
if(0 == add[N - 1]) continue; //add是阶乘求和后保存的数组
那么有了阶乘和的函数,那有哪些数需要求阶乘和呢,我打算用循环来计算21位数中0-9出现的次数
for(cot[9] = 0;cot[9] <= 9; ++cot[9])
{
for(cot[8] = 0;cot[8] <= N - cot[9]; ++cot[8])
{
for(cot[7] = 0;cot[7] <= N - cot[9] - cot[8]; ++cot[7])
{
for(cot[6] = 0;cot[6] <= N - cot[9] - cot[8] - cot[7]; ++cot[6])
{
for(cot[5] = 0;cot[5] <= N - cot[9] - cot[8] - cot[7] - cot[6]; ++cot[5])
{
for(cot[4] = 0;cot[4] <= N - cot[9] - cot[8] - cot[7] - cot[6] - cot[5]; ++cot[4])
{
for(cot[3] = 0;cot[3] <= N - cot[9] - cot[8] - cot[7] - cot[6] - cot[5] - cot[4]; ++cot[3])
{
for(cot[2] = 0;cot[2] <= N - cot[9] - cot[8] - cot[7] - cot[6] - cot[5] - cot[4] - cot[3]; ++cot[2])
{
for(cot[1] = 0;cot[1] <= N - cot[9] - cot[8] - cot[7] - cot[6] - cot[5] - cot[4] - cot[3] - cot[2]; ++cot[1])
{
cot[0] = N - cot[9] - cot[8] - cot[7] - cot[6] - cot[5] - cot[4] - cot[3] - cot[2] - cot[1];
这看起来很多,其实就是9个循环,暴力求0-9出现的次数
我们通过函数把0-9的21次方都保存到了arr[10][21]数组中了
接下来就是求add和了
int cota[10],add[N];
for(int j = 0;j < N; ++j)
{
add[j] = 0;
}
for(int k = 0;k < 10; ++k)
{
cota[k] = 0;
}
//求该数的每个位上的数字的N次方的和
for(int l = 0;l < 10; ++l) //l这个循环代表0-9数字
{
for(int m = 1;m <= cot[l]; ++m) //代表的l的数字出现的个数
{
for(int n = 0;n < N; ++n)
{
add[n] += arr[l][n]; //将计算的l的21次方保存到add数组
while(add[n] > 9) //进位操作
{
add[n] -= 10;
add[n + 1]++;
}
}
}
}
得到了总和的数之后,为了保险,我们统计一下数字,与刚一开始cot[10]数组中生成的数比较是否一致
//计数和中每个数字出现的次数
for(int o = 0;o < N; ++o)
{
cota[add[o]]++;
}
//将和中每个数字出现的次数与该数中每个数字出现的次数进行比较
int flag = 1;
for(int p = 0;p < 10; ++p)
{
if(cot[p] != cota[p])
{
flag = 0;
break;
}
}
//当该数不符合要求时执行下一次循环,不输出该数
if(0 == flag) continue;
如果一致输出这21位数,解决
下面附上源码
#include<iostream>
#define N 21
using namespace std;
void fang(int x);
int arr[10][21];
int main()
{
int cot[10];
for(int i = 0;i < 10; ++i)
{
cot[i] = 0;
fang(i);
}
//生成一个N位数并计数该数中每个数字出现的次数
for(cot[9] = 0;cot[9] <= 9; ++cot[9])
{
for(cot[8] = 0;cot[8] <= N - cot[9]; ++cot[8])
{
for(cot[7] = 0;cot[7] <= N - cot[9] - cot[8]; ++cot[7])
{
for(cot[6] = 0;cot[6] <= N - cot[9] - cot[8] - cot[7]; ++cot[6])
{
for(cot[5] = 0;cot[5] <= N - cot[9] - cot[8] - cot[7] - cot[6]; ++cot[5])
{
for(cot[4] = 0;cot[4] <= N - cot[9] - cot[8] - cot[7] - cot[6] - cot[5]; ++cot[4])
{
for(cot[3] = 0;cot[3] <= N - cot[9] - cot[8] - cot[7] - cot[6] - cot[5] - cot[4]; ++cot[3])
{
for(cot[2] = 0;cot[2] <= N - cot[9] - cot[8] - cot[7] - cot[6] - cot[5] - cot[4] - cot[3]; ++cot[2])
{
for(cot[1] = 0;cot[1] <= N - cot[9] - cot[8] - cot[7] - cot[6] - cot[5] - cot[4] - cot[3] - cot[2]; ++cot[1])
{
cot[0] = N - cot[9] - cot[8] - cot[7] - cot[6] - cot[5] - cot[4] - cot[3] - cot[2] - cot[1];
int cota[10],add[N];
for(int j = 0;j < N; ++j)
{
add[j] = 0;
}
for(int k = 0;k < 10; ++k)
{
cota[k] = 0;
}
//求该数的每个位上的数字的N次方的和
for(int l = 0;l < 10; ++l) //l这个循环代表0-9数字
{
for(int m = 1;m <= cot[l]; ++m) //代表的l的数字出现的个数
{
for(int n = 0;n < N; ++n)
{
add[n] += arr[l][n]; //将计算的l的21次方保存到add数组
while(add[n] > 9) //进位操作
{
add[n] -= 10;
add[n + 1]++;
}
}
}
}
//判断得到的和是不是一个21位数
if(0 == add[N - 1]) continue;
//计数和中每个数字出现的次数
for(int o = 0;o < N; ++o)
{
cota[add[o]]++;
}
//将和中每个数字出现的次数与该数中每个数字出现的次数进行比较
int flag = 1;
for(int p = 0;p < 10; ++p)
{
if(cot[p] != cota[p])
{
flag = 0;
break;
}
}
//当该数不符合要求时执行下一次循环,不输出该数
if(0 == flag) continue;
for(int q = N - 1;q >= 0; --q)
cout<<add[q];
cout<<endl;
}
}
}
}
}
}
}
}
}
return 0;
}
//该函数用来求x的21次方,并将所求结果存储在数组arr[x]中
void fang(int x)
{
long int a = 0,b = 0,c = 1;
for(int i = N;i > 0; --i)
{
c = c * x; //1-7位的数
a = a * x; //8-15位的数
b = b * x; //16-21位的数
while(b > 9999999) //第15的数>10;则需进位到第16位
{
b -= 10000000;
a += 1;
}
while(c > 9999999) //第7的数>10;则需进位到第8位
{
c -= 10000000;
b += 1;
while(b > 9999999) //再次判断第15位是否超过10
{
b -= 10000000;
a += 1;
}
}
}
int d;
int e = N - 14;
while(a) //将16-21位的数依次存到数组arr[x][15]-arr[x][20]
{
d = a % 10;
arr[x][N - (e--)] = d;
a = a / 10;
}
e = N - 7;
while(b) //将8-15位的数依次存到数组arr[x][7]-arr[x][14]
{
d = b % 10;
arr[x][N - (e--)] = d;
b = b / 10;
}
e = N; //将1-7位的数依次存到数组arr[x][0]-arr[x][6]
while(c)
{
d = c % 10;
arr[x][N - (e--)] = d;
c = c / 10;
}
}