2.算法分析与模拟枚举(2)
阿姆斯特朗数
今天的题型还是枚举,但是这道题让我十分抓狂,当时思考了很长时间,发现如果暴力枚举肯定会时间超限,最后还是在老师的指导下想到了用合理限度内用“空间换时间”的原则解决的。
什么是以空间换时间的原则?
以我的理解之下,时间不够用时,在合适限度内用空间换取更多时间的原则叫做“空间换时间”原则。具体意思是指在时间超限时,用打表或者调用的方式可以节省更多程序的运行时间的方法。它可以让我们的程序运行更快,时间更短,Bug更少等优点,节省更多繁琐的操作。
题目描述
编程找出所有的三位数到七位数中的阿姆斯特朗数。阿姆斯特朗数也叫水仙花数,它的定义如下:若一个n位自然数的各位数字的n次方之和等于它本身,则称这个自然数为阿姆斯特朗数。例如,153(153=1X1X1+3X3X3+5X5X5)是一个三位的阿姆斯特朗数,8208则是一个四位的阿姆斯特朗数。
输出描述
每行输出一个阿姆斯特朗数,按从小到大的顺序按行输出。
如何解决·思路(第一步)
本题的数据范围是百万级别的,如果要算时间复杂度那必定是次方级别增长,所以暴力枚举就首先被程序员否定掉了。那么应该如何解决呢?我们在开始之前应该思考一个问题,应该如何在空间允许的情况下换取更多时间来解决问题。这一点直接关联到刚才提及的“空间换时间”原则。有了这个原则之后应该怎么用呢?我们首先采取打表的方式试试看,在程序开始运行之前做个预处理,方便程序运行的时候可以直接调用,省去了复杂的计算过程。
代码如下
int a[10][10],n[10]; //定义数组a,用来做预处理
for(int i=0;i<=9;i++){ //嵌套for循环可以对二维数组进行遍历
a[i][1]=i; //将第一行设置为一到九的数字
for(int j=2;j<=7;j++){ //内层for循环用来设置次方的存储
a[i][j]=a[i][j-1]*i; //每一个数对应下标存储一到九的一到七次方
}
}
如何解决·思路(第二步)
做完预处理后,我们应该开始思考如何解决下面的问题了。那就是怎么遍历100到1000000的所有数字了。要说遍历、重复这样的工作肯定少不了for循环的牌面,并且计算机最喜欢做的就是重复干一件事,所以就写一个for循环遍历100到1000000所有整数。再将这个三到七位数依次数位分离在从表格中寻找对应的数进行求值就可以完成此操作。
代码整体理解
#include<iostream>
using namespace std;
int a[10][10],n[10];
int main(){
for(int i=0;i<=9;i++){ //预处理操作
a[i][1]=i;
for(int j=2;j<=7;j++){
a[i][j]=a[i][j-1]*i;
}
}
for(int i=100;i<=9999999;i++){ //for循环遍历
int t=i;
int nl=0;
while(t!=0){ //数位分离
nl++;
n[nl]=t%10;
t/=10;
}
int s=0;
for(int j=1;j<=nl;j++){ //整合统计
s=s+a[n[j]][nl];
}
if(s==i){
cout<<s<<endl;
}
}
return 0;
}