首先,什么是水仙花数呢?水仙花数又叫阿姆斯特朗数。具体是什么,请看链接http://baike.baidu.com/link?url=EBzzLpQqAIeFTBaOCwciWJGB0wep4kFHuG8iPg8kQcPk6L7umAFTkp-mAsMHxPoE
大概就是说,一个数有n位,这个数的每一位上的数的n次方之和等于这个数,这个数就是水仙花数。
大一的时候做过这个题,给一个位数,让求这个位数里面的水仙花数。但是因为给的位数都比较小,所以暴力之。
昨天偶然看到一个让求21位,程序要在一分钟之内完成。如果暴力,1分钟肯定不够。最后想到的方法就是:统计0——9出现的次数,算出每种情况的值,看这个值各位上0——9出现的次数是否满足用来算的情况 。这样时间就大大降低了。不过,21位依然跑了45s。(不知道还有木有更好的方法。请不要告诉我百度枚举。。。。我不再相信百度了,居然少了几个,自己程序跑居然多跑了几个出来。。。我还以为bug了呢,心想这TM要如何调试啊。结果wiki了一下,百度果然是个渣渣。不吐槽了O(∩_∩)O~)
#include<stdio.h>
#include<string.h>
#include<vector>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
#define DIGIT 21//每次就只用改变这里,就可以算出不同位数的水仙花数了。如果要想算出所用的,这里就写最大,然后再在程序里加一层循环就是咯
int Count[10];//Count用来保存枚举是0——9出现的次数,用以和算出来的值各数字出现次数进行对比。
int cnt1 ,num1[10][DIGIT+1][DIGIT+1];//cnt1是符合条件的个数。num1用来保存0——9分别出现0——DIGIT次对应的答案
char ans[10][DIGIT+1];//保存符合条件的答案
//这两个就是为了排序方便一点
vector<string> v;
string s[10];
void deal()
{
int cnt[10];//保存算出来的数0——9出现的次数,用以和Count对比看是否满足条件
int no[DIGIT+1];//算出来的数
memset(no,0,sizeof(no));
memset(cnt,0,sizeof(cnt));
for(int k = 1;k<10;k++)
{
if(num1[k][Count[k]][DIGIT]!=0)
{
return;
}
for(int i = 0;i < DIGIT;i++)
{
no[i] += num1[k][Count[k]][i];
if(no[i] > 9)
{
no[i+1] += (no[i] / 10);
no[i] %= 10;
}
}
}
if(no[DIGIT]!=0)
{
return;
}
if(no[DIGIT-1]!=0)
{
int flag = 0;
for(int j = 0;j < DIGIT;j++)
{
cnt[no[j]]++;
}
for(int j = 0;j<10;j++)
{
if(cnt[j]!=Count[j])
{
flag = 1;
break;
}
}
if(!flag)
{
ans[cnt1][DIGIT] = '\0';
for(int j = 0 ,k = DIGIT - 1;j < DIGIT;j++,k--)
{
ans[cnt1][k] = no[j] + '0';
}
s[cnt1] = ans[cnt1];
v.push_back(s[cnt1]);
cnt1++;
}
}
};
int main()
{
//计算从0——9出现分别0——DIGIT次时的值
for(int i = 1;i<10;i++)
{
num1[i][1][0] = 1;
int index = 0;
for(int j = 1;j<=DIGIT;j++)
{
for(int r = 0;r<=index;r++)
{
num1[i][1][r] *= i;
}
for(int r = 0;r<=index;r++)
{
if(num1[i][1][r] > 9)
{
num1[i][1][r+1] += (num1[i][1][r] / 10);
num1[i][1][r] %= 10;
}
}
while(index < DIGIT-1 && num1[i][1][index+1] > 0)
{
index++;
if(num1[i][1][index] > 9)
{
num1[i][1][index+1] += (num1[i][1][index] / 10);
num1[i][1][index] %= 10;
}
}
}
for(int j = 2;j<=DIGIT;j++)
{
for(int r = 0;r<=DIGIT;r++)
{
num1[i][j][r] = num1[i][1][r] * j;
}
for(int r = 0;r<DIGIT;r++)
{
if(num1[i][j][r] > 9)
{
num1[i][j][r+1] += (num1[i][j][r] / 10);
num1[i][j][r] %= 10;
}
}
}
}
//枚举0——9分别出现0——DIGIT次的情况,0——9分别对应a——j
for(int a = 0;a<=DIGIT;a++)
{
Count[0] = a;
for(int b = 0;b<=DIGIT;b++)
{
if(a + b > DIGIT)//保证出现的次数不大于DIGIT,下同
{
break;
}
Count[1] = b;
for(int c = 0;c<=DIGIT;c++)
{
if(a + b + c > DIGIT)
{
break;
}
Count[2] = c;
for(int d = 0;d<=DIGIT;d++)
{
if(a + b + c + d > DIGIT)
{
break;
}
Count[3] = d;
for(int e = 0;e<=DIGIT;e++)
{
if(a + b + c + d + e > DIGIT)
{
break;
}
Count[4] = e;
for(int f = 0;f<=DIGIT;f++)
{
if(a + b + c + d + e + f > DIGIT)
{
break;
}
Count[5] = f;
for(int g = 0;g<=DIGIT;g++)
{
if(a + b + c + d + e + f + g > DIGIT)
{
break;
}
Count[6] = g;
for(int h = 0;h<=DIGIT;h++)
{
if(a + b + c + d + e + f + g + h> DIGIT)
{
break;
}
Count[7] = h;
for(int i = 0;i<=DIGIT;i++)
{
if(a + b + c + e + f + g + h + i > DIGIT)
{
break;
}
Count[8] = i;
int j = DIGIT - a - b - c - d - e - f - g - h - i;
if(j < 0)
{
break;
}
Count[9] = j;
deal();
}
}
}
}
}
}
}
}
}
//排序,将答案从小到大输出
sort(v.begin(),v.end());
for(int i = 0;i<v.size();i++)
{
cout<<v[i]<<endl;
}
return 0;
}