パズル問題解法のアルゴリズム講座
![]() |
この問題に先ほどのバックトラックを使っても失敗します。何故なら
「堂々巡り」という現象が発生してしまうからです。
堂々巡りとは、局面Aから局面Bへと変化しさらに局面Cへと探索が
進んでいったが、もしいつしか元の局面Aに変化してしまったらこれま
での探索の過程が繰り返し実行されてしまいます。これでは無限地獄。
これを防止するには、探索過程の総ての局面を保存しておいて過去に
同じ局面がなかったかをチェックしながら探索しなければなりません。
そうなると次のことが問題となります。
膨大な量の保存局面の中からいかに速く指定の局面を探し出すか?
ひとつひとつ照合したのでは探索時間がバカになりません。ここで登場するのがハッシュ法です。
/* ハッシュ関数 */
int hash_func() {
int hash; /* ハッシュ値 */
long num = 0;
/* 局面を数値化しハッシュ値を求める */
for (局面の全位置をスキャンする)
num = (num << 2) + (その位置のデータ);
hash = (int)(num % M);
for (;;) {
if (格納番地hashの局面 == 未使用) break; /* カラの格納場所発見 */
if (格納番地hashの局面 == 今の局面) break; /* 同型がすでにあった */
hash = (hash + 1) % M; /* 異なる局面で使用済 */
}
return hash;
}
|
C言語ソースリスト
Javaアプレットの実行 |
なんとなく理解して頂けたと思いますが、この方法をどう具体的に実現すれ
ばよいのか。それには、待ち行列(キュー)を使うと簡単に実現出来ます。
待ち行列とは、列の先頭から順に出番が来て、あとから来た人は列の後ろへ
並びジッと自分の出番が来るのを待っています。そして、この列には局面を保
存した時の格納番地を入れておけばいいのです。
int QUEUE[M]; /* 待ち行列 */
int Qtop; /* 待ち行列の先頭位置 */
int Qend; /* 待ち行列の後ろ位置 */
while (Qtop < Qend) {
address1 = QUEUE[Qtop++]; /* キュー先頭より取る */
address1に保存してある局面を呼び出す;
for (1手加えて新たな局面を順次生成する) {
address2 = hash_func(); /* 格納番地を求める */
if (address2の中 == カラ) { /* 未登録なら登録 */
この局面をaddress2に保存する;
QUEUE[Qend++] = address2; /* キュー後ろに追加 */
}
if (解を発見した) return 発見しました;
}
}
return 解が在りません;