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

8 Puzzle

The goal of the 8 puzzle problem is to complete pieces on $3 \times 3$ 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 8 as shown below.

1 3 0
4 2 5
7 8 6

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 0

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

Input

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

Output

Print the fewest steps in a line.

Constraints

There is a solution.

Sample Input

1 3 0
4 2 5
7 8 6

Sample Output

4

Solution in C# (judge verdict: Time Limit Exceeded)

using System;
using System.Linq;
using System.Collections.Generic;



public class EightPuzzle
{
    public static void Main()
    {
        var inputs = Console.ReadLine().Split(' ').Select(int.Parse)
            .Concat(Console.ReadLine().Split(' ').Select(int.Parse))
            .Concat(Console.ReadLine().Split(' ').Select(int.Parse))
            .Cast<int>()
            .ToArray();
        
        var board = new Board(inputs);
        
        var max = 0;
        var boards = new [] {board};
//        var sw = new Stopwatch();
        while (true)
        {
            max++;
//            max.Dump("?????????max?????????");
//            sw.Restart();
            boards = boards.SelectMany(x => x.Move(max))
                .ToArray();
//            sw.Stop();
//            sw.ElapsedMilliseconds.Dump("move");
//            sw.Restart();
            if (boards.Any(x => x.Nodes.All(node => node.IsCorrect())))
                break;
//            sw.Stop();
//            sw.ElapsedMilliseconds.Dump("all");
        }
        
        Console.WriteLine(max);
    }
}

public class Board
{
    public Node[] Nodes { get; set; }
    private int MoveCount { get; set; }
    static HashSet<Board> hash;
    public Board(IEnumerable<int> inputs)
    {
        Nodes = inputs.Select((x, i) => new Node((i + 1) % 9, x))
            .ToArray();
        hash = new HashSet<Board>(); 
    }
    
    public Board() { }
    
    public Board[] Move(int max)
    {
        MoveCount++;
        
//        var sw = Stopwatch.StartNew();
        
        var empty = Nodes.First(x => x.Current == 0);
        var children = empty.AdjacentNumbers
            .Select(_ => Board.Clone(this))
            .ToArray();
        
//        sw.Stop();
//        sw.ElapsedMilliseconds.Dump("clone");
//        sw.Restart();
        
        empty.AdjacentNumbers
            .Select((adj, i) => 
            {
                var board = children[i];
                var left = board.Nodes.First(x => x.Current == 0);
                var right = board.Nodes.First(x => x.CorrectNumber == adj);
                
                if (left.LastNumber == right.Current)
                {
                    children[i] = null;
                    return 0;
                }
                board.SwapNode(left, right);
                
                if (!hash.Add(board))
                    children[i] = null;
                return 0;
            })
            .ToArray();
        
//        if (children.Where(x => x != null).Any(x => x.Nodes.All(node => node.IsCorrect())))
//        {
//            return children.Where(x => x != null).Where(x => x.Nodes.All(node => node.IsCorrect())).ToArray();
//        }
            return children.Where(x => x != null).ToArray();
        
//        if (MoveCount == max)
//            return children.Where(x => x != null).ToArray();
//        
//        return children.Where(x => x != null)
//            .SelectMany(x => x.Move(max))
//            .ToArray();
    }
    
    public int SwapNode(Node left, Node right)
    {
        left.LastNumber = left.Current;
        right.LastNumber = right.Current;

        left.Current = right.LastNumber;
        right.Current = left.LastNumber;
        return 0; // dummy
    }
    
    private static Board Clone(Board board)
    {
        return new Board
        {
            Nodes = board.Nodes.Select(Node.Clone)
                .ToArray(),
            MoveCount = board.MoveCount
        };
    }

    public override string ToString()
    {
        return Nodes.Select(x => x.Current)
            .Select(x => x.ToString())
            .Aggregate((acc, x) => acc + " " + x);
    }
    
    public override int GetHashCode()
    {
        var code = Nodes.Select(x => x.Current).Aggregate((accum, x) => accum * 10 + x);
        return code;
    }
    public override bool Equals(Object o)
    {
        return Equals((Board)o);
    }
    public bool Equals(Board other)
    {
        return ToString() == other.ToString();
    }
}

public class Node
{
    private static Dictionary<int, int[]> adjacentNumbersDic =
        new Dictionary<int, int[]>
        {
            { 1, new [] { 2, 4 } },
            { 2, new [] { 1, 3, 5 } },
            { 3, new [] { 2, 6 } },
            { 4, new [] { 1, 5, 7 } },
            { 5, new [] { 2, 4, 6, 8 } },
            { 6, new [] { 3, 5, 0 } },
            { 7, new [] { 4, 8 } },
            { 8, new [] { 5, 7, 0 } },
            { 0, new [] { 6, 8 } },
        };

    public int CorrectNumber { get; private set; }    
    public int Current { get; set; }
    public int LastNumber { get; set; }
    public int[] AdjacentNumbers { get { return adjacentNumbersDic[CorrectNumber]; } }

    public Node(int correct, int current, int lastNumber = -1)
    {
        CorrectNumber = correct;
        Current = current;
        LastNumber = lastNumber;
    }
    
    public static Node Clone(Node node)
    {
        return new Node(node.CorrectNumber, node.Current, node.LastNumber);
    }
    
    public bool IsCorrect() { return CorrectNumber == Current; }
}