Problem:
MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], processEscapes: true }});

15 Puzzle

The goal of the 15 puzzle problem is to complete pieces on $4 \times 4$ cells where one of the cells is empty space.

In this problem, the space is represented by 0 and pieces are represented by integers from 1 to 15 as shown below.

1 2 3 4
6 7 8 0
5 10 11 12
9 13 14 15

You can move a piece toward the empty space at one step. Your goal is to make the pieces the following configuration in the shortest move (fewest steps).

1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 0

Write a program which reads an initial state of the puzzle and prints the fewest steps to solve the puzzle.

Input

The $4 \times 4$ integers denoting the pieces or space are given.

Output

Print the fewest steps in a line.

Constraints

The given puzzle is solvable in at most 45 steps.

Sample Input

1 2 3 4
6 7 8 0
5 10 11 12
9 13 14 15

Sample Output

8

Solution in Ruby (judge verdict: Time Limit Exceeded)

$mdt = Array.new(16){Array.new(16){0}}
16.times{|i|
  16.times{|j|
    $mdt[i][j] = ((i/4) - (j/4)).abs + ((i%4)-(j%4)).abs
  }
}

class Puzzle
  attr_accessor :mat, :step, :cost, :zero
  def initialize(mat, step, zero)
    @mat = mat
    @step = step
    @cost = distance
    @zero = zero
  end
  def >(other)
    return self.cost + self.step < other.cost + other.step ? true : false
  end
  def <(other)
    return self.cost + self.step > other.cost + other.step ? true : false
  end
  def distance
    # goal = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0]
    d = 0
    15.times{|n|
      m = @mat.index(n+1)
      d += $mdt[n][m]
    }
    return d
  end
end

class Heep
  def initialize
    @node = []
  end
  def insert(num)
    i = @node.size
    @node[i] = num
    p = (i+1)/2-1
    while i > 0 && @node[p] < @node[i]
      @node[i], @node[p] = @node[p], @node[i]
      i = p
      p = (i+1)/2-1
    end
  end
  def extract
    ret = @node[0]
    if @node.size > 1
      @node[0] = @node.pop()
      maxHeapify(0)
    else
      @node = []
    end
    return ret
  end
  def maxHeapify(i)
    h = @node.size
    largest = i
    l = 2 * i + 1
    largest = l if l < h && @node[l] > @node[largest]
    r = 2 * i + 2
    largest = r if r < h && @node[r] > @node[largest]
    if largest != i then
      @node[i], @node[largest] = @node[largest], @node[i]
      maxHeapify(largest)
    end
  end
  def size
    return @node.size
  end
  def contain(node)
    if @node.index(node) == nil
      return false
    else
      return true
    end
  end
end

mat = []
4.times{|i|
  mat[4*i],mat[4*i+1],mat[4*i+2],mat[4*i+3] = gets.split.map(&:to_i)
}

ini = Puzzle.new(mat, 0, mat.index(0))
q = Heep.new
q.insert(ini)

done = {}
loop do
  break if q.size == 0
  it = q.extract
  if it.cost == 0 then
    p it.step
    exit
  else
    done[it.mat] = true
  end
  idx = it.zero
  x = idx % 4
  y = idx / 4

  #Down
  unless y == 0 then
    mat = it.mat.clone
    mat[idx], mat[idx-4] = mat[idx-4], mat[idx]
    unless done[mat]
      tmp = Puzzle.new(mat, it.step+1, idx-4)
      q.insert(tmp)
    end
  end

  #Up
  unless y == 3 then
    mat = it.mat.clone
    mat[idx], mat[idx+4] = mat[idx+4], mat[idx]
    unless done[mat]
      tmp = Puzzle.new(mat, it.step+1, idx+4)
      q.insert(tmp)
    end
  end

  #Left
  unless x == 0 then
    mat = it.mat.clone
    mat[idx], mat[idx-1] = mat[idx-1], mat[idx]
    unless done[mat]
      tmp = Puzzle.new(mat, it.step+1, idx-1)
      q.insert(tmp)
    end
  end

  #Right
  unless x == 3 then
    mat = it.mat.clone
    mat[idx], mat[idx+1] = mat[idx+1], mat[idx]
    unless done[mat]
      tmp = Puzzle.new(mat, it.step+1, idx+1)
      q.insert(tmp)
    end
  end

end