Posted by yama3 2011年 09月 19日
No Comments
Google Developer DayのDev Quizに関して, 既に締め切りからかなり経ってしまい今更な感じはありますが, どうせだしということで, 自分がどのようにスライドパズルに挑んだかを書いてみようかと思います.
問題文
幅が 3 マスから 6 マスで、高さが 3 マスから 6 マスのボードが与えられます。 各マスは、パネルが置かれているか、壁があるか、空白であるかのいずれかです。 パネルには 1 から 9 あるいは A から Z のいずれかの文字が書かれており、同じ文字の書かれたパネルは存在しません。 壁は 0 個以上存在し、空白のマスはただ 1 つだけ存在します。
空白は、上下左右のマスのパネルと入れ替えることができます。上のマスのパネルと入れ替えることを U とよび、同様に、下左右のマスのパネルと入れ替えることをそれぞれ D, L, R とよぶものとします。壁を空白やパネルと入れ替えることはできません。
パズルを解くというのは、与えられたボードの各マスを操作して、ゴール状態に持っていくことです。
ゴール状態とは、上の行から各行順番に、左から右に 1, 2, 3, 4, …, 9, A, …, Z という順にパネルが並び、最も右下のマスに空白が配置された状態のことです。壁のあるマスに対応するパネルは存在しません。例えば、左上のマスが壁であれば、ボード上に 1 のパネルは存在しません。
いま、使うことができる L, R, U, D それぞれの総数があたえられます。 この総数は全パズルで共有されています。 例えばあるパズルを解くために L を使い切ってしまった場合、 他のパズルでは L を使うことはできません。 この総数を超えないようにしながら、なるべくたくさんのパズルを解いてください。
実際に与えられた問題は合計で5,000問あり, かなりの量の問題を解く必要があります。
自分の書いたプログラムの概略
まずは用いたプログラミング言語はC++になります. ほかの問題なんかでは, プログラムの書きやすさなどからPHPを使ったりしたものもあるのですが, こういったプログラムの書きやすさより, アルゴリズムやデータ構造部分が変更しやすかったり, 実行速度そのものが早かったり, メモリの確保できる容量に制限のないC++のほうが向いているという判断です.
パズルの局面探索ということで, おおまかなアルゴリズムとしては, 幅優先探索を採用. ただし, 幅優先探索で素直に実装してしまうと, 探索空間の大きさが半端なく大きいことから, メモリが足りなくなってしまったり, 計算時間が膨大になってしまうことから, いろいろな工夫が必要になります.
まずは深さに制限を与えることから
メモリが足りなくなってしまう点を打開するために, まずはある程度の深さまで探索を行い, 解を得られなければその問題に関しては解を得ることを諦めて次の問題にいくようにします. また問題を与えられた時点で, 問題のサイズが大きければその時点で解の探索すら行わないようにすることで, 50問くらいを解くことができたようです.
続きを読む