#問題
1 ~ 100までの番号が書かれた100枚のカードが順番に並べられています。
最初、全てのカードは裏返しの状態で置かれています。
ある人が2番のカードから、1枚おきにカードを裏返していきます。
すると、2, 4, 6,・・・, 100番のカードが表を向くようになります。
次に、別の人が、3番のカードから2枚おきにカードを裏返していきます。
(裏向きのカードは表を向き、表を向いているカードは裏返されます。)
また、次の人が、4番のカードから3枚おきに、カードを裏返していきます。
このようにn番目のカードからn - 1枚おきにカードを裏返す操作を、
どのカードも向きも変わらなくなるまで続けたとします。
カードの向きが変わらなくなった時、
裏向きになっているカードの番号をすべて求めてください。
| | | | | | | | | |・・・
↓ ↓ ↓ ↓
| |2| |4| |6| |8| |・・・
↓ ↓ ↓
| |2|3|4| | | |8|9|・・・
↓ ↓
| |2|3| | | | | |9|・・・
引用「プログラマ脳を鍛える数学パズル 著者 増井 敏克」
#回答
n = 100
cards = [False] * n
for i in range(2, 101):
j = i - 1
while j < n:
cards[j] = not cards[j]
j += i
for i in range(n):
if not cards[i]:
print(i + 1)
for i in range(1, 101):
flag = False
for j in range(1, 101):
if i % j == 0:
flag = not flag
if flag:
print(i)
#つまづいたところ
今までと比べるとスムーズに解くことができました。
強いて申し上げるなら、この書籍の回答ではrubyで書かれていたのですが、
その中の!cards[j]
の意味を調べるのに時間がかかりました。
「ビックリマーク」とか「おったまげンションマーク」としか知らなかったのですが、
「感嘆符(かんたんふ)」もしくは「エクスクラメーションマーク」というんですね。
なんだ、「おったまげンションマーク」って笑
話がそれてしまいましたが、
この!cards[j]
の!
は否定(not)を表していることがわかりました。
pythonではrubyのように感嘆符 + 変数名では書けない※ので、
これをpython形式に書き換えます。
その形がnot cards[j]
です。
※2分ぐらいしかググっておりません。誤っているようでしたらお申し付けください。
もともとこのcards
にはfalse
が100個入っています。
カードが裏返っている状態をfalse
として表しているので、
true
が表向きの状態となりますね。
そのfalse
をwhile文の中でnot
を使い、
false
からtrue
にしたり、true
からfalse
にしています。
プログラム中の最後に裏向きのカードを出力するようにしているので、
if not cards[i]: print(i + 1)
という書き方になります。
さて、このanswer_1.py
からこの問題の答えが出ましたが、
書籍中にも書かれておりますポイントがこの問題にはあります。
それは、
左から順番に処理をするということは、
「すでに通過した部分については反転しない」と言い換えることができます。
引用「プログラマ脳を鍛える数学パズル 著者 増井 敏克」
ということだそうです。
それを踏まえて書き直したのがanswer_2.py
になります。
どういう風にtrue
とfalse
を繰り返しているのかというと、
ここですね。if i % j == 0: flag = not flag
解説はぜひこの著書を読んで欲しいのと、
数学的な部分が関わり私では説明できないので割愛しますが、
「平方数」やら「約数」やらが関わっているそうです。
それでは以上になります。
今回もご拝読ありがとうございました。