第一章 前言
1.1 参考文献
郭继展,郭勇,苏辉《程序算法与技巧精选》,机械工业出版社,2008年5月第一版,ISBN 978-7-111-23816-4,第7.3节:求自幂数——用数组预作乘法提高速度100倍。
1.2 写此文章的目的
(1)想用自己的语言总结书上的内容;
(2)用自己的笔记本电脑测试下各个方法间,效率差距究竟有多大;
(3)用自己的风格写一遍代码,加深对知识的理解,也方便以后自己复习。
1.3 自幂数定义
http://b.baidu.cn/view/8059450.htm1.4 文章概述
我会先在第二章讨论各种算法的效率问题,并贴所有源代码供读者验证,也对结果进行截图方便不愿跑代码的懒读者快速读完本篇文章。在第三章写一段计算所有自幂数的小程序。
PS:本来排版很好的,涉及到英文的书写时,博客给我自动换行换到难看死了……
第二章 算法之间的差距
2.1 最原始的思路
把pow(10,x-1)至pow(10,x)内的所有数遍历一遍,来求x位自幂数,。
#include <iostream>
#include <cmath>
#include <ctime>
using namespace std;
clock_t start__;
#define tic start__=clock()
#define toc cout<<(clock()-start__)*1000/CLOCKS_PER_SEC<<"ms\n"
void zms1(int x) // 自幂数拼音首字母:zms,后缀+数字用于区别不同算法的zms函数
{
int l=pow(10,x-1),r=pow(10,x),i,i0,j,t,a;
for(i=l; i<r; i++)
{
i0 = i; // 拷贝i的一个副本
for(t=j=0;j<x;j++)
{
a = i0%10; // 得到最末位的值
t += a*pow(10,j)-pow(a,x);
i0 /= 10;
}
if(t==0) cout<<i<<endl;
}
}
int main()
{
tic,zms1(7),toc;
return 0;
}
2.2 用各个位的分别穷举代替一个值的穷举
因为算法涉及到一个值各个位上的操作,每次需要进行a=i0%10; i0/=10;等操作。以七位自幂数为例,我们不妨穷举7个位上的每个值来求解。当然,这样的弊端是,函数的清晰度会降低,也无法像zms1一样具有通用性——可以通过输入参数x,求任意x位的自幂数。优点是降低循环内部的操作次数,效率会提升。我单写一个七位自幂数的函数zms2来验证。
#include <iostream>
#include <cmath>
#include <ctime>
using namespace std;
clock_t start__;
#define tic start__=clock()
#define toc cout<<(clock()-start__)*1000/CLOCKS_PER_SEC<<"ms\n"
void zms2()
{
int i,j,k,l,m,n,o; //用来穷举各个位的值的变量,即值本身为ijklmno
for(i=1;i<10;i++) for(j=0;j<10;j++) for(k=0;k<10;k++)
for(l=0;l<10;l++) for(m=0;m<10;m++) for(n=0;n<10;n++) for(o=0;o<10;o++)
{
if(pow(i,7)+pow(j,7)+pow(k,7)+pow(l,7)+pow(m,7)+pow(n,7)+pow(o,7)
==1000000*i+100000*j+10000*k+1000*l+100*m+10*n+o)
cout<<i<<j<<k<<l<<m<<n<<o<<endl;
}
}
int main()
{
tic,zms2(),toc;
return 0;
}
zms2中,判断一个数是否为自幂数的方法如if语句中所写的式子,非常清晰易懂。而zms1中方法换汤不换药,在数学里,要判断两个表达式f(x)与g(x)是否相等,可以定义h(x)=f(x)-g(x),如果h(x)恒等于0,则f(x)=g(x)。此处道理相同,相当于用t来存储右式1000000*i+100000*j+10000*k+1000*l+100*m+10*n+o减去左式pow(i,7)+pow(j,7)+pow(k,7)+pow(l,7)+pow(m,7)+pow(n,7)+pow(o,7)的值,如果结果为t==0,则为七位自幂数。在后续的程序中,我们主要使用zms1的自幂数判断方法,用这种方法才能方便的存储中间计算值和进行回溯运算。
再回到zms1和zms2的效率分析上,zms2因为少了对原值各个位的拆解运算,效率提高了1倍多。
2.3 事先存储中间运算量
再仔细分析语句:pow(i,7)+pow(j,7)+pow(k,7)+pow(l,7)+pow(m,7)+pow(n,7)+pow(o,7)==1000000*i+100000*j+10000*k+1000*l+100*m+10*n+o,因为i,j...o只能取0~9的值,在计算pow(?,7)方面,只有10种运算——pow(0,7),pow(1,7),pow(2,7)...pow(9,7)。这意味着什么呢?在zms2进行的7*(1千万-1百万)=6300万次运算中,跑的7次幂部分,其实只有10种结果!相当于一套10道题的试卷,让你重复做630万次!!!在pow(10,?)中,也是一样的道理。
于是,我们就想到&