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;
using System.Threading;

public class Parallel
{
    public static void ForEach<T>(IEnumerable<T> items, Action<T> action)
    {
        if (items == null)
            throw new ArgumentNullException("enumerable");
        if (action == null)
            throw new ArgumentNullException("action");

        var resetEvents = new List<ManualResetEvent>();

        foreach (var item in items)
        {
            var evt = new ManualResetEvent(false);
            ThreadPool.QueueUserWorkItem((i) =>
            {
                action((T)i);
                evt.Set();
            }, item);
            resetEvents.Add(evt);
        }

        foreach (var re in resetEvents)
            re.WaitOne();
    }
}

public static class a
{
	public static void ForEach<T>(this IEnumerable<T> e, Action<T, int> action)
	{
		var i = 0;
		foreach (var element in e) action(element, i++);
	}

}

public class EightPuzzle
{
    public static void Main()
    {
        ThreadPool.SetMinThreads(8, 8);
        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 count = 0;
        var boards = new [] { new Board(inputs) };
        while (!boards.Any(x => x.Nodes.All(node => node.IsCorrect())))
        {
            count++;
            boards = boards.SelectMany(x => x.Move())
                .ToArray();
        }
        
        Console.WriteLine(count);
    }
}

public class Board
{
    public Node[] Nodes { get; set; }
    static HashSet<int> hash = new HashSet<int>();
    public Board(IEnumerable<int> inputs)
    {
        Nodes = inputs.Select((x, i) => new Node((i + 1) % 9, x))
            .ToArray();
    }
    
    public Board() { }
    
    public Board[] Move()
    {
        var empty = Nodes.First(x => x.Current == 0);
        var children = empty.AdjacentNumbers
            .Select(_ => Board.Clone(this))
            .ToArray();
        
        Parallel.ForEach(Enumerable.Range(0, empty.AdjacentNumbers.Count()),
            i =>
            {
                var adj = empty.AdjacentNumbers[i];
                var board = children[i];
                var left = board.Nodes.First(x => x.Current == 0);
                var right = board.Nodes.First(x => x.CorrectNumber == adj);
                
                board.SwapNode(left, right);
                
                if (!hash.Add(board.GetHash()))
                    children[i] = null;
            });
//        empty.AdjacentNumbers
//            .ForEach((adj, i) =>
//            {
//                var board = children[i];
//                var left = board.Nodes.First(x => x.Current == 0);
//                var right = board.Nodes.First(x => x.CorrectNumber == adj);
//                
//                board.SwapNode(left, right);
//                
//                if (!hash.Add(board.GetHash()))
//                    children[i] = null;
//            });
        
        return children.Where(x => x != null).ToArray();
    }
    
    public void SwapNode(Node left, Node right)
    {
        var temp = left.Current;
        left.Current = right.Current;
        right.Current = temp;
    }
    
    private static Board Clone(Board board)
    {
        return new Board
        {
            Nodes = board.Nodes.Select(Node.Clone)
                .ToArray(),
        };
    }

//    public override string ToString()
//    {
//        return Nodes.Select(x => x.Current)
//            .Select(x => x.ToString())
//            .Aggregate((acc, x) => acc + " " + x);
//    }
    
    public int GetHash()
    {
        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 readonly 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[] AdjacentNumbers { get; set; }

    public Node(int correct, int current)
    {
        CorrectNumber = correct;
        Current = current;
        AdjacentNumbers = adjacentNumbersDic[correct];
    }
    
    public static Node Clone(Node node)
    {
        return new Node(node.CorrectNumber, node.Current);
    }
    
    public bool IsCorrect() { return CorrectNumber == Current; }
}