首先,什么是水仙花数呢?水仙花数又叫阿姆斯特朗数。具体是什么,请看链接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; }