私自身が表題の問題を解いた時のプログラムについて解説します。
問題の詳細は「上下反転した数字表示器」(CodeIQ)を参照してください。
図のような7セグメントディスプレイを使った数字表示器があります。
この数字表示器を上下逆さに置いたとき、例えば「0625」は「5290」と読むことができます。
逆さに置いたときに対応する数字は以下のようになります。
0 <-> 0
1 <-> 1
2 <-> 2
5 <-> 5
6 <-> 9
8 <-> 8
(「1」は反転すると位置がずれますが、「1」として読み取ることが可能なものとします。)
n 桁を表示できる数字表示器を通常の置き方で置いた時よりも、上下逆さに置いた場合の方が大きな値として読み取ることができるものが何通りあるかを求めるプログラムを作成してください。
例えば、n = 2のとき、以下の21通りがあります。
01, 02, 05, 06, 08, 09, 12, 15, 16, 18, 19, 25, 26, 28, 29, 56, 58, 59, 66, 68, 86
標準入力から自然数 n が与えられますので、パターン数を標準出力に出力してください。
なお、n は最大で20とします。
【入出力サンプル】
標準入力
2
標準出力
21
Rubyで解答しています。
#!/usr/bin/ruby def solve(n, cnt, base) # printf("cnt=%d, base=%d\n", cnt, base) if cnt == n then return base end if cnt == 0 then base = 1 elsif cnt == 1 then base = 7*(base+2) elsif cnt % 2 == 0 then a = base/7**(cnt/2-1)+1 base = 7**(cnt/2)*a # printf("a=%d, base=%d\n", a, base) else a = base/7**(cnt/2)+2 base = 7**(cnt/2+1)*a # printf("a=%d, base=%d\n", a, base) end return solve(n, cnt+1, base) end # main while line = gets line.strip! if line.empty? then next end p solve(line.to_i, 0, 0) end
コードは難しくありませんが、問題は難しいです。
パターン数が非常に多いので計算だけで解けるようにしないと時間切れは確実です。
n | 答え | パターン | 更にパターン |
---|---|---|---|
1 | 1 | 1 | 1 |
2 | 21 | 7*3 | 7*(1+2) |
3 | 154 | 7*22 | 7*(21+1) |
4 | 1176 | 7*7*24 | 72*(22+2) |
5 | 8281 | 72*169 | 72*(7*24+1) |
6 | 58653 | 72*7*171 | 73*(169+2) |
7 | 410914 | 73*1198 | 73*(7*171+1) |
8 | 2881200 | 74*1200) | 74*(1198+2) |
入力値を数値にしてsolve()に渡し、結果を印字します。
再帰関数になっています。
nは入力値、cntは何回目の操作か、baseは前回の結果です。
cntが0始まりなので注意してください。
cntがnに等しいなら答えがも止まっているのでbaseを返却します。
7〜17行目は考え方に書いた法則を実装しています。
cnt==0の時とcnt==1の場合を特別扱いして以降の計算の初期値としています(cnt==1の条件は不要にできたと思います)。
考え方の表の赤字、青字部分はn-1の結果から必要な回数7で割って求めて+1か+2し、必要な回数7を掛けて計算しています。
再帰呼び出しが返ってきたらそのまま結果として返却します。
うまく法則に気づけたのでできましたが諦めていてもおかしくなかった問題と思います。
一応真ん中の数字から左右に数字をつけて行く方法でも実際の値を作らずパターン数だけを数えることができそうなのですが、実装していないのでできるかどうかはちょっとわかりません。