|
このように方針が立つと,あとはいかにコップの移動をプログラム上で実装するか(つまり,コップがそれぞれのトレイにある状態をどのように表現するとトレースのシミュレーションが容易になるか)という点だけである. コップはそれまでに積み重ねられている上に重ねて置くしかないことと,重ねられた山の一番上のものを取ることしか許されていないが,このようなデータの挿入削除の制限を持った構造は スタック (stack) という名前で良く知られているものである.スタックをプログラムで実装する方法を使えば容易にプログラムは書けるが,たとえスタックというものを知らなくても,似たようなことを行うのはむずかしいことではない.
さて実は,このように実際にコップの移動をトレースしてみなくても,ステップ数は式の計算によって求めることもできる.
トレイ A, B, C に重ねられているコップの大きさ(整数値)の集合をそれぞれ A, B, C で表すことにする(集合について知らない人は読み飛ばしてもよい.予選の参加者がこのような解法をすることは出題側では想定していない).また,初期状態 A, B, C から,トレイ X にすべてのコップを重ねるために必要な最小ステップ数を fX(A, B, C) で表すことにする(X は A, B, C のいずれか).A ∪ B ∪ C の中の最小値を min で表す.また,空集合を 0 で表す.
まず,fC(A, B, C) は fA, fB を使って次のように表すことができる.
この問題は「ハノイの塔」と呼ばれる有名な問題をもとにしている.ハノイの塔の問題では,この問題のコップに相当するものの移動は A から C へも,C から A へも直接移動できることになっているが,この問題はそれらを禁止したものである.容易にわかるように,A にすべてのコップがある状態から C にすべてのコップを重ねた状態にするための最小ステップ数はハノイの塔の問題では 2n - 1 であり,この問題では上述のように 3n - 1 である.この問題の場合,3n は可能なコップの配置状態の総数に等しい.A にすべてのコップがある状態から C にすべてのコップがある状態へ移るためには,B にすべてのコップが重ねられている状態を必ず通過し,それは,移動の過程のちょうど真ん中の (3n - 1)/2 ステップ目である.
最後に,別の解法も可能であることも指摘しておく.それは,8クイーン問題とか騎士の周遊問題といった有名問題を解くときに用いられる方法,すなわち,可能なステップの進め方を先へ先へと進めて,失敗したら最小限後戻りして別の可能なステップを先へと進める,という方法である(グラフ理論とアルゴリズムの用語を使って言うと,可能なステップの状態を頂点とし,移動可能なステップ間に辺があるようなグラフを底優先探索することに等しい.通常はそのようなグラフは意識せずに,ステップの進め方を再帰的なアルゴリズムとして記述することが多い).しかし,この問題の場合,ステップ数が最悪の場合 3n - 1 にもなるので,n がちょっと大きくなるだけで,それまでにたどって来た道筋を(失敗したときに後戻り [バックトラッキング (backtracking) という] できるように)記憶しておく必要がある [再帰的プログラムの場合には,再帰が発生するたびにそのときの関数の局所状態がメモリ内にシステムによって自動的に記憶される] )ために,メモリが実行時にオーバーフローしてしまうという決定的な欠点がある.
さらに,別の解法として,どの状態からも「A から B」「B から A」「B から C」「C から B」の 4 通りしかコップの移動方法がないので,m 桁の 4 進数(m ステップ分のコップの移動を表す)すべてを系統的に生成して,そのうちで実際にコップの移動に対応しているものを求めるという解法もある(全数検査法).しかし,この方法では,4m 通りの場合すべてを試さなければならないので,ごく小さい m にしか対応できないという致命的欠点がある.
それでも,全数検査法で解けば 4 点(手で計算することも可能),再帰で解けば 12 点取れるように入力データを決めて出題した.また,n およびそれに対応して決まる m の値の上限は,最小ステップ数が 32 ビット数で表現できる範囲内に抑えた.