裏 RjpWiki

Julia ときどき R, Python によるコンピュータプログラム,コンピュータ・サイエンス,統計学

カプレカ数

2015年03月16日 | ブログラミング

0 から 1000 までのカプレカ数を求めよとのことだ...

カプレカ数とは馴染みのないものであるが,定義は 2 通りあるそうだ。

1. 2 乗して前の部分と後ろの部分に分けて(偶数桁 2n 桁である場合は先頭 n 桁と末尾 n 桁に分け,奇数桁 2n + 1 桁である場合は先頭 n 桁と末尾 n + 1 桁に分けて)和を取ったとき,元の値に等しくなるもの。

2. 桁を並べ替えて最大にしたものから最小にしたものの差を取ったとき,元の値に等しくなるもの。

今回は,前者のことをいっているようだ。

Wikipedia で調べると
カプレカ数
1, 9, 45, 55, 99, 297, 703, 999, 2223, 2728, 4879, 4950, 5050, 5292, …(オンライン整数列大辞典の数列 A006886 http://oeis.org/A006886)が簡単に見つかる。
プログラムを書いて,0 ~ 5300 の範囲を探索すると,得られる出力と違うところがある。

a1 = 0:5300
a2 = a1^2
old = options(scipen=10)
a3 = strsplit(as.character(a2), "")
options(old)
a4 = sapply(a3, function(x) {
            y = unlist(x)
            n = length(y)
            if (n == 1) {
              as.numeric(paste(y, collapse=""))
            } else {
              m = n %/% 2
              as.numeric(paste(y[1:m], collapse="")) + as.numeric(paste(y[(m+1):n], collapse=""))
            }
          })
a1[a1 == a4]

> a1[a1 == a4]
 [1]    0    1    9   45   55   99  297  703  999 2223 2728 4950 5050

0 は明白な カプレカ数だと思うがそれはさておき,プログラムによる出力には 4879 はない。4879^2 = 2380 と 4641 なので,2380 + 4641 = 7021 になるので,カプレカ数ではないはず。2380 の最後の 0 を無視するというルールならば,238 + 4641 = 4879 になるのでカプレカ数ということになるのだが。同様に,5292^2 = 2800 と 5264 なので,28 + 5264 = 5292 ではあるが?と根拠を求めてネットサーフィンすると,

Karekar numbers
http://www.numbersaplenty.com/set/Kaprekar_number/

に,

Note that the second part can start with zero:  5292^2 = {28} {005264}  and 28+5264=5292.

と書いてあった。後ろ半分の数字の前に 0 があってもよいということは,前の部分の後ろの 0 は無視してもよいということである(無視しない場合も考えよということ)。このルールも加えてプログラムを修正する。

プログラムに for を使うことになったがやむを得ない。

N = 5300
a1 = 0:N
a2 = a1^2
old = options(scipen=10)
a3 = strsplit(as.character(a2), "")
options(old)
a4 = a5 = integer(N+1)
for (i in seq_along(a1)) {
  y = unlist(a3[[i]])
  n = length(y)
  if (n == 1) {
    a4[i] = a5[i] = as.numeric(paste(y, collapse=""))
  } else {
    m = n %/% 2
    a4[i] = as.numeric(paste(y[1:m], collapse="")) + # 前半分の後ろの 0 を無視しない
            as.numeric(paste(y[(m+1):n], collapse=""))
    a5[i] = as.numeric(paste(gsub("0*$", "", y[1:m]), collapse="")) + # 前半分の後ろの 0 を無視する
            as.numeric(paste(y[(m+1):n], collapse=""))
  }
}
a1[a1 == a4 | a1 == a5] # 前半分の後ろの 0 を無視しない場合と無視する場合のどちらか一方でも可ということで

> a1[a1 == a4 | a1 == a5]
 [1]    0    1    9   45   55   99  297  703  999 2223 2728 4879 4950 5050 5292

Wikipedia などの例示と一致した。

10 万までで 5 秒弱かかって,以下の結果を得る。

> print(a1[a1 == a4 | a1 == a5])})
 [1]     0     1     9    45    55    99   297   703   999  2223  2728  4879  4950  5050  5292  7272
[17]  7777  9999 17344 22222 38962 77778 82656 95121 99999

コメント    この記事についてブログを書く
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする
« 完全数を探せ | トップ | カプレカ数(その2) »
最新の画像もっと見る

コメントを投稿

ブログラミング」カテゴリの最新記事