クラスタリングアルゴリズムにより、解くと絵が浮かび上がる 迷路を作成する方法を紹介する。
ウェブのリンク情報や、mixiの友人関係など、ネットワークの性質を 知りたいことがよくある。このとき、ネットワークの性質として
などの情報が欲しくなる。このような解析をするときに 必要となるのがクラスタリングである。
- このネットワークにおいて任意に選んだ要素Aと要素Bはつながっているか?
- このネットワークは全体がつながっているか?
- つながっていないとしたらいくつのグループに分かれるか?
- 要素数最大のグループはどれか?
クラスタリングとは、同値関係のリストが与えられたときにグループ分けを することである。たとえば、
友達の友達は友達であると定義すると、友人関係は同値関係を作る。 その上で、
クラスタリングアルゴリズムはいくつか知られているが、 そのうち一次元配列を使った簡単な例を紹介する。
この作業はリンクリストの作成である。 下図では、6つの要素からなるリンクリストが、 クラスタリングにより2つにグループ分けされた様子を示す。 最初、すべての要素のリンクは自分を指しているが、 クラスタリングにより、必ず番号の低い側(図では左側)にリンクされる。 このとき、自分からたどっていったリンクの終点の要素の番号が 自分のクラスタ番号となる。
以上の作業をコードで書くと以下のようになる。 pair1[i]とpair2[i]に同値関係が入っているとして、 関数clusteringを呼んでやればクラスタリングができる。 あとは int get_cluster_numberに要素番号を入れれば その要素のクラスタ番号が返ってくるので、あとは 最大クラスタを探すなり、クラスタの数を数えるなりすることができる。
//--------------------------------------------------------------------------- int cluster[N]; int pair1[N_PAIR],pair1[N_PAIR]; //--------------------------------------------------------------------------- int get_cluster_number(int index){ int i = index; while(i != cluster[i]){ i = cluster[i]; } return i; } //--------------------------------------------------------------------------- void clustering(void){ for(int i=0;i < N;i++){ cluster[i] = i; } for(int i=0;i < N_PAIR;i++){ int i1 = pair1[i]; int i2 = pair2[i]; i1 = get_cluster_number(i1); i2 = get_cluster_number(i2); if(i1 < i2){ cluster[i2] = i1; }else{ cluster[i1] = i2; } } } //---------------------------------------------------------------------------
では、クラスタリングを迷路作成に応用してみよう。 迷路を作成するには、基本的には枝をつけるだけでよい。 しかし、適当に枝を伸ばすと、 「入り口からいけない場所(死に領域)ができる」 「ループができてしまい、解答が一意でなくなる」 などの問題ができてしまう。 そこで、クラスタリングを使って解答のパスが一意で、 なおかつ死に領域ができないことを保証する。
迷路の作成アルゴリズムは以下の通り。
部屋を要素とし、通し番号をつけておく
ランダムに壁を壊す。このとき、隣あう部屋がつながったとしてクラスタリングする
同じクラスタ番号に属す部屋の間の壁(下図の赤い線)は壊さない (ループを作らない保証)。
すべてが同じクラスタ番号に属すまで続ける(死に領域が出来ない保証)
以上のアルゴリズムを用いて、「解くと絵が浮かび上がる迷路」を 作ることができる。やり方は簡単で、先に解答のパスを作り、その部分だけ クラスタリングしてから壁を壊し始めれば、ループを作らない保証から 与えた解答が最短距離となる迷路が出来上がる。 以下の図はそのようにして作成した迷路の例である。 左図の迷路を解くと、右図のような絵が浮かび上がる。
クラスタリングアルゴリズムを応用し、 「解くと絵が浮かび上がる迷路」を 作成してみた。クラスタリングはあらゆるネットワークの解析に使えるし、 コードも20行もないので知っていて損はないアルゴリズムである。