パズルを解くコードを、あなたは書けるか?
アルゴリズムがみるみるわかる!プログラミングってやっぱり面白い!
急速な技術の進歩、システム開発競争の激化……。プログラマを取り巻く環境はやさしいものではありません。でも、思い出してみてください。自分の書いたソースコードでプログラムが動くのを初めて見たとき。思い描いた通りのプログラムができたとき。プログラミングの楽しさを感じたことでしょう。何もないところからソースコードだけで新たな価値を生むプログラマは、非常に魅力的な職業です。
本書で登場する数学パズルは、そのようなワクワクにあふれています。「両替したときの硬貨の組み合わせはいくつ?」のような問題から、「国名でしりとりしたときに、一番長く続く順番は?」「運命の出会いは何通り?」というものまで、70の問題を解くコードを、3人のキャラクターたちと一緒に考えていきます。
パズルを解くうちにアルゴリズムが身につき、シンプルで高速なコードが書けるようになります。楽しみながらスキルアップもできて一石二鳥。さっそく挑戦してみましょう!
【使用言語について】
本書の解説では、主にRubyとJavaScriptを使用していますが、解説内容は「考え方」が中心であるため、どんな言語にも応用できます。また、問題を解くために特定の言語が必要になることもありません。
【本書に収録されている問題(抜粋)】
Q01 10進数で回文
Q03 カードを裏返せ
Q08 優秀な掃除ロボット
Q09 つりあわない男女
Q21 排他的論理和で作る三角形
Q33 百人一首の達人
Q45 素数のマトリックス
Q48 グレイコードのループ
Q53 いたずらされたお菓子
Q64 迷路で待ち合わせ
※本電子書籍は同名出版物を底本として作成しました。記載内容は印刷出版当時のものです。
※印刷出版再現のため電子書籍としては不要な情報を含んでいる場合があります。
※印刷出版とは異なる表記・表現の場合があります。予めご了承ください。
※プレビューにてお手持ちの電子端末での表示状態をご確認の上、商品をお買い求めください。
(翔泳社)
お問い合わせ
内容についてのお問い合わせは、正誤表、追加情報をご確認後に、お送りいただくようお願いいたします。
正誤表、追加情報に掲載されていない書籍内容へのお問い合わせや
その他書籍に関するお問い合わせは、書籍のお問い合わせフォームからお送りください。
利用許諾に関するお問い合わせ
本書の書影(表紙画像)をご利用になりたい場合は書影許諾申請フォームから申請をお願いいたします。
書影(表紙画像)以外のご利用については、こちらからお問い合わせください。
ご購入いただいた書籍の種類を選択してください。
刷数は奥付(書籍の最終ページ)に記載されています。
現在表示されている正誤表の対象書籍
書籍の種類:
書籍の刷数:
本書に誤りまたは不十分な記述がありました。下記のとおり訂正し、お詫び申し上げます。
対象の書籍は正誤表がありません。
最終更新日:2018年12月10日
発生刷 |
ページ数 |
書籍改訂刷 |
電子書籍訂正 |
内容 |
登録日 |
1刷 |
041
Q09 問題文 |
3刷 |
済 |
誤 |
2つのグループのいずれかで男女の数が異なってしまう |
正 |
2つのグループのいずれも男女の数が異なってしまう |
|
2015.12.16 |
1刷 |
088
Q19 解答の補記(カッコ内) |
3刷 |
済 |
誤 |
これを満たす組み合わせは以下のようになります。 |
正 |
これを満たす組み合わせの例は以下のようになります。 |
|
2015.12.10 |
1刷 |
100
Q23 ソースコード(q23_01.rb)の5行目と6行目(空行含む) |
3刷 |
済 |
誤 |
return 1 if depth == 0
return 0 if coin == 0 |
正 |
return 0 if coin == 0
return 1 if depth == 0 |
備
考 |
第3刷発行にあわせ、ダウンロードファイルを修正しました(2016.3.3) |
|
2015.11.11 |
1刷 |
100
Q23 解答 |
3刷 |
済 |
誤 |
16195220通り |
正 |
16051010通り |
|
2015.11.11 |
1刷 |
124
Q30 ソースコード(q30_01.rb) |
3刷 |
済 |
誤 |
N = 20
def set_tap(remain) return 1 if remain == 1 cnt = 0 # 2口 (1..(remain / 2)).each{|i| cnt += set_tap(remain - i) * set_tap(i) } # 3口 (1..(remain / 3)).each{|i| (1..((remain - i) / 2)).each{|j| cnt += set_tap(remain - (i + j)) * set_tap(j) * set_tap(i) } } cnt end puts set_tap(N)
|
正 |
N = 20
def set_tap(remain) return 1 if remain == 1 cnt = 0 # 2口 (1..(remain / 2)).each{|i| if remain - i == i then cnt += set_tap(i) * (set_tap(i) + 1) / 2 else cnt += set_tap(remain - i) * set_tap(i) end } # 3口 (1..(remain / 3)).each{|i| (i..((remain - i) / 2)).each{|j| if (remain - (i + j) == i) && (i == j) then cnt += set_tap(i) * (set_tap(i) + 1) * (set_tap(i) + 2) / 6 elsif remain - (i + j) == i then cnt += set_tap(i) * (set_tap(i) + 1) * set_tap(j) / 2 elsif i == j then cnt += set_tap(remain - (i+j)) * set_tap(i) * (set_tap(i)+1) / 2 elsif remain - (i + j) == j then cnt += set_tap(j) * (set_tap(j) + 1) * set_tap(i) / 2 else cnt += set_tap(remain - (i + j)) * set_tap(j) * set_tap(i) end } } cnt end puts set_tap(N)
|
備
考 |
第3刷発行にあわせ、ダウンロードファイルを修正しました(2016.3.3) |
|
2015.11.25 |
1刷 |
125
Q30 ソースコード(q30_02.rb) |
3刷 |
済 |
誤 |
N = 20 @memo = {1 => 1}
def set_tap(remain) return @memo[remain] if @memo.has_key?(remain) cnt = 0 # 2口 (1..(remain / 2)).each{|i| cnt += set_tap(remain - i) * set_tap(i) } # 3口 (1..(remain / 3)).each{|i| (1..((remain - i) / 2)).each{|j| cnt += set_tap(remain - (i + j)) * set_tap(j) * set_tap(i) } } @memo[remain] = cnt end
puts set_tap(N)
|
正 |
N = 20
@memo = {1 => 1} def set_tap(remain) return @memo[remain] if @memo.has_key?(remain) cnt = 0 # 2口 (1..(remain / 2)).each{|i| if remain - i == i then cnt += set_tap(i) * (set_tap(i) + 1) / 2 else cnt += set_tap(remain - i) * set_tap(i) end } # 3口 (1..(remain / 3)).each{|i| (i..((remain - i) / 2)).each{|j| if (remain - (i + j) == i) && (i == j) then cnt += set_tap(i) * (set_tap(i) + 1) * (set_tap(i) + 2) / 6 elsif remain - (i + j) == i then cnt += set_tap(i) * (set_tap(i) + 1) * set_tap(j) / 2 elsif i == j then cnt += set_tap(remain - (i+j)) * set_tap(i) * (set_tap(i)+1) / 2 elsif remain - (i + j) == j then cnt += set_tap(j) * (set_tap(j) + 1) * set_tap(i) / 2 else cnt += set_tap(remain - (i + j)) * set_tap(j) * set_tap(i) end } } @memo[remain] = cnt end
puts set_tap(N)
|
備
考 |
第3刷発行にあわせ、ダウンロードファイルを修正しました(2016.3.3) |
|
2015.11.25 |
1刷 |
126
Q30 ソースコード(q30_03.js) |
3刷 |
済 |
誤 |
const N = 20; var memo = []; memo[1] = 1;
function set_tap(remain){ if (memo[remain]){ return memo[remain]; } var cnt = 0; /* 2口 */ for (var i = 1; i <= remain / 2; i++){ cnt += set_tap(remain - i) * set_tap(i); } /* 3口 */ for (var i = 1; i <= remain / 3; i++){ for (var j = 1; j <= (remain - i) / 2; j++){ cnt += set_tap(remain - (i + j)) * set_tap(j) * set_tap(i); } } memo[remain] = cnt; return cnt; }
console.log(set_tap(N));
|
正 |
const N = 20; var memo = []; memo[1] = 1;
function set_tap(remain){ if (memo[remain]){ return memo[remain]; } var cnt = 0; /* 2口 */ for (var i = 1; i <= remain / 2; i++){ if (remain - i == i) cnt += set_tap(i) * (set_tap(i) + 1) / 2; else cnt += set_tap(remain - i) * set_tap(i); } /* 3口 */ for (var i = 1; i <= remain / 3; i++){ for (var j = i; j <= (remain - i) / 2; j++){ if ((remain - (i + j) == i) && (i == j)) cnt += set_tap(i) * (set_tap(i) + 1) * (set_tap(i) + 2) / 6; else if (remain - (i + j) == i) cnt += set_tap(i) * (set_tap(i) + 1) * set_tap(j) / 2; else if (i == j) cnt += set_tap(remain - (i+j)) * set_tap(i) * (set_tap(i)+1) / 2; else if (remain - (i + j) == j) cnt += set_tap(j) * (set_tap(j) + 1) * set_tap(i) / 2; else cnt += set_tap(remain - (i + j)) * set_tap(j) * set_tap(i); } } memo[remain] = cnt; return cnt; }
console.log(set_tap(N));
|
備
考 |
第3刷発行にあわせ、ダウンロードファイルを修正しました(2016.3.3) |
|
2015.11.25 |
1刷 |
126
Q30 解答 |
3刷 |
済 |
誤 |
136916765通り |
正 |
63877262通り |
|
2015.11.25 |
1刷 |
198
下から4行目(Q48の「Point」最後の行) |
4刷 |
済 |
誤 |
排他的論理和を計算すると「49B」になります。 |
正 |
排他的論理和を計算すると「495」になります。 |
|
2018.12.10 |
1刷 |
212
Q51 解答 |
3刷 |
済 |
誤 |
①2(n-1)回で「初めて」元に戻ったとき、46個
②何度も元に戻るが、2(n-1)回のときも元に戻ったとき、22個 |
正 |
①2(n-1)回で「初めて」元に戻ったとき、22個
②何度も元に戻るが、2(n-1)回のときも元に戻ったとき、46個 |
|
2015.12.10 |
1刷 |
212
Q51のPoint内、下から3つ目の式 |
4刷 |
済 |
誤 |
(i×2)2(n-1)mod(2×n-1)=i |
正 |
i×22(n-1)mod(2×n-1)= i |
|
2016.11.16 |