幅優先探索

11月 12th, 2008 admin Posted in アルゴリズムとデータ構造 |

昨日に続き「アルゴリズムとデータ構造シリーズ」です。今回は第10章「バックトラック法と幅優先探索」の幅優先探索です。

幅優先探索

前回やったバックトラック法はとてもパワフルなアルゴリズムなのですが、必ずしも最適解が求まるわけではないという問題によっては不都合な特徴もあります。そこで総当たりかつ最適な解をみつけるためのアルゴリズムが幅優先探索法になります。
幅優先探索は、その名のとおり幅を優先させた探索で、まず1回目の試行でできるすべてのパターンをためし、次に2回目の試行でできるすべてのパターンをためし・・・とやっていく方法です。
バックトラック法が木構造を右手法で巡回したのに対し、こちらは1個目のノードをすべて試す、そしたら次に2階層目のノードを試すとやっていく感じです。

コード

セブンパズルというパズルを解くコードを書きました。

RUBY:
  1. class Pattern
  2.   attr_accessor :hash, :pattern_from
  3.  
  4.   def initialize(hash, pattern_from)
  5.     @hash = hash
  6.     @pattern_from = pattern_from
  7.   end 
  8. end
  9.  
  10. class SevenPuzzle
  11.   def initialize
  12.     @history = Array.new
  13.     @ans = Marshal.dump([1,2,3,4,5,6,7,0])
  14.   end
  15.  
  16.   def save_history(pattern, pattern_from)
  17.     hash = Marshal.dump(pattern)
  18.     @history.each do |a|
  19.       return if a.hash == hash
  20.     end
  21.    
  22.     @history.push(Pattern.new(hash, pattern_from))
  23.   end
  24.  
  25.   def solve
  26.     pattern = Array.new(8)
  27.  
  28.     queue_bottom = 0
  29.     until @history.size == 0 do
  30.       hash = @history.shift.hash
  31.       return true if hash == @ans
  32.  
  33.       pattern = Marshal.load(hash)
  34.      
  35.       blank_pos = pattern.index(0)
  36.  
  37.       if blank_pos> 3
  38.         pattern[blank_pos] = pattern[blank_pos - 4]
  39.         pattern[blank_pos - 4] = 0
  40.         save_history(pattern, queue_bottom)
  41.         pattern = Marshal.load(hash)
  42.       end
  43.  
  44.       if blank_pos <4
  45.         pattern[blank_pos] = pattern[blank_pos + 4]
  46.         pattern[blank_pos + 4] = 0
  47.         save_history(pattern, queue_bottom)
  48.         pattern = Marshal.load(hash)
  49.       end
  50.  
  51.       if blank_pos != 0 && blank_pos != 4
  52.         pattern[blank_pos] = pattern[blank_pos - 1]
  53.         pattern[blank_pos - 1] = 0
  54.         save_history(pattern, queue_bottom)
  55.         pattern = Marshal.load(hash)
  56.       end
  57.  
  58.       if blank_pos != 3 && blank_pos != 7
  59.         pattern[blank_pos] = pattern[blank_pos + 1]
  60.         pattern[blank_pos + 1] = 0
  61.         save_history(pattern, queue_bottom)
  62.         pattern = Marshal.load(hash)
  63.       end
  64.      
  65.       queue_bottom += 1
  66.     end
  67.     return false
  68.   end
  69. end
  70.  
  71. #initial pattern
  72. pattern = [2,7,4,3,0,5,1,6]
  73.  
  74. p = SevenPuzzle.new
  75. p.save_history(pattern, -1)
  76.  
  77. if p.solve
  78.     p 'done'
  79. else
  80.     p 'not found'
  81. end

まとめ

今回はキューを使って解きました。バックトラック法がスタックを使っていたのにたいして、こちらがキューを使うというのがなんだか面白いです。データ構造でも対になっているものがあるんですね。

※このシリーズは私がRubyでアルゴリズムとデータ構造を基礎から学ぶ記録です。全体の目次はこちらへ。

Leave a Reply