問題4 解説

 この問題は今のところ効率的に解く方法が知られていない有名な問題の1つである.したがって,すべての可能性をしらみつぶしに試していく方法を用いるしかない.
 この問題の場合,最も長い鎖を求めるために,深さ優先探索 (DFS: depth-first search) と呼ばれる再帰的な方法で解くことが,一般的な解法である. 深さ優先探索とは,リングから紐を順序良くたどって行くときに,各リングにあるどれか1つの紐を選び,先へ先へと行けるところまで行き,行き止まりに達するかまたはすでにたどったリングに達したときには1つ手前のリングまで戻って別の紐を選んでいく,という方法である.このとき,同じ経路を何度もたどらないように記録を残しておけば(すなわち,すでに通った紐に印を付けることにより,わかるようにしておけば),この方法で全体をくまなく探索することができる.
 解を求めるのにかかる時間はばらつきが大きく一定しないが,最も単純で記述しやすい方法であるため,広く用いられている.

 この深さ優先探索を実現する方法の1つに再帰呼出し (recursive call) がある.再帰呼出しとは,自分自身を呼び出すことである.しかしながら,常に自分自身を呼び出すわけではない.そうでないと永遠に終了しなくなってしまう.そこで,自分自身の呼び出しを終了するための条件を与えることが重要である. この問題の場合,あるリングからいくつかの紐がたどれるので,その先のリングについて探索する部分で自分自身を呼び出していくことになる.そして,行き止まりに達するか,またはすでにたどったリングに達したときが自分自身の呼び出しを終了するときである.

 再帰呼出しは一般的なデータ構造であるスタックと関係が深い.内部的には再帰呼出しはスタックを用いて実現されることが多いため,自分のプログラム中でスタックを用いることで再帰呼出しを行わないようにすることもできる.これは高速化につながることもあるが,プログラムが複雑化することにもなり,どちらが良いかは問題の性質等による.
 すでにこれまでの解説の中に何回もスタックが登場しているが,それはそれだけスタックが有用なデータ構造であるということである.繰り返しになるが,スタックとは,最後に入力したデータが先に出力される (LIFO: Last In First Out) というデータ構造である.本を机の上に積み上げるような構造になっており,本を積むときは一番上に積み(プッシュ (push) という),本を取り出すときは一番上にある本から順次取り出していく(ポップ (pop) という)しかないようなものである.

 深さ優先探索ではすべての可能性をしらみつぶしに試していくことになるが,実際には,探索の途中で引き返すことができるので,純粋な総当りよりは効率が良くなる.ある解を求めるときに,可能性のある手順を順に試していき,その手順では解が求められないと判明した時点で一つ前の状態に戻って別の手順を試す,という方法のことをバックトラッキング (backtracking) という(すでに別の解説でも述べた).