检查一个数字是否为Munchhausen数

什么是Munchhausen数

Munchhaussen数,是指一个自然数可以拆分成若干个数字(一般是十进制下的各个位上的数字),然后再将这些数字分别提高到自己次幂的和,如果这个自然数等于这些和的和,则称这个自然数为Munchhausen数。Munchhausen数最常见的是10进制下的Munchhausen数,其中最小的Munchhausen数是1,第二小的是343,第三小的是69,665。

Munchhausen数的发现

Munchhausen数是对义大利童话故事中彭瑟哈斯(Baron M¨unchhausen)的褒奖。彭瑟哈斯以富有的幽默和诙谐见长。他忠于祖国地位使他成为普鲁士国王的高级侍从,这给他提供了机会用这些故事来取乐;他甚至有了自己的舞台上的表演!MVC的发现者也有一些很棒的故事,使得他的名字与算法体系结构,Logo语言和许多奇妙的想法联系在一起。这里给出其中一个它有趣的故事,其中提到了Munchhausen数:

当帕帕斯·基翁尼(Papass Kionni)得知勒那德(Leonhard)大数也可以称作超倍数时,他开始将大数解释为它本身各位上提高次幂和。勒那德与他的朋友约翰尼斯·乔治·范德莱芬(Johann Georg von Soldner)发现,数407是由“4”的4次幂,“0”的0次幂,“7”的5次幂组成的。他们活动范围扩大到更大的数,发现了85, 405和1634。他们呈报了这些信息,并推测26,415是也是。在极端的情况下,他们找到了一个上限,即4个数均不超过10。不幸的是,25.769也被加入了他们的名单。幸运的是,没人受到伤害。

如何判断Munchhausen数

既然了解了Munchhausen数的定义,那么如何判断一个数字是否为Munchhausen数呢?

暴力枚举法

我们可以将该数字每个数位上的数提高次幂相加,判断和是否等于原数。下面我们看看C++的代码:

bool isMunchhausen(int num){

int tmp = num, sum = 0;

while(tmp){

int digit = tmp % 10;

tmp /= 10;

sum += pow(digit, digit);

}

return sum == num;

}

以上是暴力枚举法的代码实现。

值得注意的是,如果我们使用pow函数来计算次幂的话,会产生精度误差,因此可以自行写一个用于计算次幂的函数。下面是精度更高的版本:

int power(int base, int exponent){

int result = 1;

while(exponent){

if(exponent & 1) result *= base;

base *= base;

exponent >>= 1;

}

return result;

}

bool isMunchhausen(int num){

int tmp = num, sum = 0;

while(tmp){

int digit = tmp % 10;

tmp /= 10;

sum += power(digit, digit);

}

return sum == num;

}

进一步优化

以上算法虽然简单易懂,但是时间复杂度较高。我们可以优化这个算法,用一个数组f表示数字i是否为Munchhausen数。然后用双指针法,通过不断更改f数组中的值,来判断每个数字是否为Munchhausen数。下面是C++代码实现:

bool isMunchhausen(int num){

static int f[10] = {0, 1, 1, 0, 1, 0, 0, 0, 1, 0};

int tmp = num, sum = 0;

while(tmp){

int digit = tmp % 10;

tmp /= 10;

sum += f[digit];

}

return sum == num;

}

void getMunchhausenNum(){

for(int i = 1; i <= 10000000; i++){

if(isMunchhausen(i)) cout << i << endl;

}

}

代码中f[10]数组表示待判断数的最大位数,数组下标表示数字的各个位数,f[i]记录i的i次幂是否出现过。如果数字数位较大,则需要增加f数组的长度。

结语

Munchhausen数虽然非常罕见,但是对于数字相关的研究来说,是一个有趣的话题。如果你感兴趣,可以尝试使用回溯算法来寻找更多的Munchhausen数。

后端开发标签