「すべて見つける」ということなので、何も考えないと無限に探索しないといけません。
そこで、まず探索範囲を見積もります。
おそらく、どこかで桁数を増やせば増やすほどもとの数の方が大きくなり、
操作結果が追いつかなくなるでしょう。
当然9をいっぱい使うほうが操作結果が大きくなるため、
9を並べた数とその操作結果を調べてみます。
コード:
数 操作結果
999999999 3486784401
9999999999 3874204890
99999999999 4261625379
9を10個並べた時、もとの数の方が操作結果より大きくなりました。
よって、きちんと証明はしていませんが、10桁以下の数だけ調べればよさそうです。
また、この結果より、任意の10桁以下の数について、
操作結果は3874204890より大きくならないことがわかります。
この値なら、32ビット符号なし整数に収まりそうです。 (符号付きだとダメです)
あとは、単純に探索していきましょう。
現代のPCであれば、数分もあれば終わるはずです。
再帰は、累乗の計算に用います。
aのb乗は、bが偶数のとき(a×a)の(b÷2)乗、
bが奇数のとき((a×a)の((b-1)÷2)乗)×a、と表すことができる性質を用います。
ただし、毎回計算するのは効率が悪いので、
最初に各数字の累乗を配列に格納しておきます。
コード:
#include <stdio.h>
unsigned int ruizyo(unsigned int a, unsigned int b) {
if (b == 0) {
if (a == 0) return 0; else return 1;
} else if (b == 1) {
return a;
} else if (b % 2 == 0) {
return ruizyo(a * a, b / 2);
} else {
return a * ruizyo(a * a, (b - 1) / 2);
}
}
int main(void) {
const unsigned int MAX = 4000000000u;
unsigned int i;
unsigned int r[10];
for (i = 0; i < 10; i++) {
r[i] = ruizyo(i, i);
}
for (i = 1; i < MAX; i++) {
unsigned int sum = 0;
unsigned int value;
for (value = i; value > 0; value /= 10) {
sum += r[value % 10];
}
if (sum == i) {
printf("%u\n", i);
}
}
return 0;
}
おまけ:出てきた数をOEIS(オンライン整数列大辞典)に入れて検索した結果
A046253 - OEIS