algorithm 15 puzzle problem - andstudy/forge GitHub Wiki

CynicJJ

  • 50๋‹จ๊ณ„๋Š” ์ปค๋…• 20๋‹จ๊ณ„ ๋„˜๊ธฐ๊ธฐ๋„ ํž˜๋“œ๋„ค...
  • ์ด๋ฒˆ ์Šคํ„ฐ๋””๋„ ์ฐธ์„ ๋ชปํ•จ. 3๋ฒˆ ์—ฐ์† ๋ถˆ์ฐธํ•˜๋‹ˆ ๊ฐ‘๊ฐ‘ํ•˜๋„ค...

!ModuleMain.vb

    Module ModuleMain
    
    	Sub Main()
    
    		Dim notSolvable(,) As Byte = New Byte(,) { _
    		 {13, 1, 2, 4}, _
    		 {5, 0, 3, 7}, _
    		 {9, 6, 10, 12}, _
    		 {15, 8, 11, 14}}
    
    		Dim solvable(,) As Byte = New Byte(,) { _
    		 {2, 3, 4, 0}, _
    		 {1, 5, 7, 8}, _
    		 {9, 6, 10, 12}, _
    		 {13, 14, 11, 15}}
    
    		Console.WriteLine(GetPuzzleResult(notSolvable))
    		Console.WriteLine(GetPuzzleResult(solvable))
    	End Sub
    
    	Function GetPuzzleResult(ByVal board As Byte(,)) As String
    		Dim aPuzzle As Puzzle = New Puzzle
    
    		aPuzzle.Setup(board)
    		aPuzzle.DoSolve()
    
    		If aPuzzle.IsSolved() Then
    			Return aPuzzle.SolvingPath
    		Else
    			Return "This puzzle is not solvable."
    		End If
    
    	End Function
    
    End Module

Position.vb

    Public Class Position
    
    	Public Row As Integer
    	Public Column As Integer
    
    	Sub New(ByVal row As Integer, ByVal column As Integer)
    		Me.Row = row
    		Me.Column = column
    	End Sub
    End Class

Puzzle.vb

    ' ๊ฒฐ๋ก ๋ถ€ํ„ฐ ๋งํ•˜๋ฉด ๋ฌธ์ œ ํ’€์ด ์‹คํŒจ
    ' 50๋‹จ๊ณ„๊นŒ์ง€ ๊ฒ€ํ† ํ•˜๋ผ๊ณ  ํ–ˆ์œผ๋‚˜ 20๋‹จ๊ณ„ ๋„˜์œผ๋ฉด ์‹คํ–‰์‹œ๊ฐ„์ด 1๋ถ„์„ ๋„˜๊ธด๋‹ค -_-
    ' ์—ฌ๋Ÿฌ ๋ฐฉ๋ฒ•๋“ค์„ ์‹œ๋„ํ•ด ๋ดค์œผ๋‚˜ ํšจ๊ณผ๊ฐ€ ์—†์–ด์„œ ์‚ญ์ œ
    ' ๋ญ”๊ฐ€ ์š”๋ น์ด ์—†๋Š” ๊ฑธ๊นŒ.. ๋ƒ ..
    ' ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ๋˜๋Š”๊ฑธ๊นŒ... ์ฉ์ฉ
    
    Public Class Puzzle
    
    	' ์ž…๋ ฅ๋œ ๊ฒฝ๋กœ์— ๋”ฐ๋ผ ์ด๋™
    	Sub MoveByPath(ByVal path As String)
    		Dim dirs() As Char = path.ToCharArray()
    		For Each dir As Char In dirs
    			Select Case dir
    				Case "R"c
    					MoveRight()
    				Case "L"c
    					MoveLeft()
    				Case "U"c
    					MoveUp()
    				Case "D"c
    					MoveDown()
    			End Select
    		Next
    	End Sub
    
    	' ๋ชจ๋“  ๊ฐ€๋Šฅํ•œ ๊ฒฝ๋กœ๋ฅผ ๋งŒ๋“ ๋‹ค
    	' ๊ฒฝ๋กœ๋Š” ๊ณต๋ฐฑ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด์„œ 4์˜ ์ง€์ˆ˜์Šน์œผ๋กœ ๊ฐฏ์ˆ˜๊ฐ€ ๋Š˜์–ด๋‚œ๋‹ค
    	' ๊ธฐํ•˜๊ธ‰์ˆ˜์ ์œผ๋กœ ๋Š˜์–ด๋‚˜๋Š” ๊ฒฝ๋กœ๋ฅผ ์–ด๋–ป๊ฒŒ ์ค„์ผ๊ฒƒ์ธ๊ฐ€๊ฐ€ ๊ด€๊ฑด
    	' ์ด๋™์—†์Œ : ""
    	' ํ•œ๋ฒˆ์ด๋™ : R L U D
    	' ๋‘๋ฒˆ์ด๋™ : RR LR UR DR LR LL UL DL RU LU UU DU RD LD UD DD
    	' ์„ธ๋ฒˆ์ด๋™ : RRR LRR URR DRR LRR LLR ...
    	' ๋„ค๋ฒˆ์ด๋™ : RRRR LRRR ...
    	' ...
    	Sub GetNextTryPaths(ByVal tryPaths As List(Of String))
    		' ์ด์ „ ๋‹จ๊ณ„ ๊ฒฝ๋กœ๋“ค ์ž„์‹œ ๋ณด๊ด€
    		Dim oldPaths As List(Of String) = New List(Of String)
    		oldPaths.AddRange(tryPaths)
    
    		' ๋ช‡๋ฒˆ์ด๋™ ํ•˜๋Š”๊ฐ€
    		Dim steps As Integer = tryPaths(0).Length
    
    		' ์‹œ๋„ํ•ด ๋ณผ ๊ฒฝ๋กœ๋“ค์„ ์ƒˆ๋กœ ๋งŒ๋“ ๋‹ค
    		tryPaths.Clear()
    
    		Dim dirs() As String = {"R", "L", "U", "D"}
    		For Each dir As String In dirs
    			For Each path As String In oldPaths
    
    				' ์ด์ „ ์ž๋ฆฌ๋กœ ๋˜๋Œ์•„ ๊ฐ€๋Š” ๊ฒฝ๋กœ๋Š” ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์Œ
    				If steps >= 1 Then
    					Dim lastDir As String = path.Substring(path.Length - 1)
    					If lastDir = "L" And dir = "R" Then Continue For
    					If lastDir = "R" And dir = "L" Then Continue For
    					If lastDir = "D" And dir = "U" Then Continue For
    					If lastDir = "U" And dir = "D" Then Continue For
    				End If
    
    				' ๋‹ค๋ฅธ ์—ฌ๋Ÿฌ ๋ฐฉ๋ฒ•์„ ์จ ๋ดค์œผ๋‚˜ ๋ณ„ ํšจ๊ณผ ์—†์—ˆ์Œ. ๋ญ”๊ฐ€ ์š”๋ น์ด ์—†๋Š” ๊ฑธ๊นŒ.. ๋ƒ ..
    
    				' ์ƒˆ๋กœ์šด ๊ฒฝ๋กœ๊ฐ€ ์œ ํšจํ•œ ๊ฒฝ๋กœ(ํผ์ฆ ๋ฐ–์œผ๋กœ ๋‚˜๊ฐ€์ง€ ์•Š๋Š”)๋ผ๋ฉด ์ถ”๊ฐ€
    				Dim newPath As String = path + dir
    				If IsValidMove(newPath) Then tryPaths.Add(newPath)
    			Next
    		Next
    	End Sub
    
    	' ๋ฌธ์ œ ํ’€์ด
    	Sub DoSolve()
    		Dim stepCount As Integer = 0
    
    		Dim tryPaths As List(Of String) = New List(Of String)
    		tryPaths.Add("")
    
    		While stepCount <= 12		' 50๋‹จ๊ณ„๋Š” ์ปค๋…• 20๋‹จ๊ณ„ ๋„˜๊ธฐ๊ธฐ๋„ ํž˜๋“ค๋‹ค
    			For i As Integer = 0 To tryPaths.Count - 1
    				' ์ดˆ๊ธฐ์ƒํƒœ๋กœ ๋งŒ๋“ค๊ณ  ๊ฒฝ๋กœ์— ๋”ฐ๋ผ ์ด๋™
    				Reset()
    				MoveByPath(tryPaths(i))
    
    				' ํ’€๋ ธ์œผ๋ฉด ์ค‘๋‹จ
    				If IsSolved() Then
    					_solvingPath = tryPaths(i)
    					Exit While
    				End If
    			Next
    
    			' ํ’€๋ฆฌ์ง€ ์•Š์•˜๋‹ค๋ฉด ๋‹ค์Œ ๋‹จ๊ณ„๋กœ
    			GetNextTryPaths(tryPaths)
    			stepCount += 1
    		End While
    	End Sub
    
    	' ๋‹ค ํ’€๋ ธ๋‚˜?
    	Function IsSolved() As Boolean
    		If 0 <> _board(3, 3) Then Return False
    		If 15 <> _board(3, 2) Then Return False
    		If 14 <> _board(3, 1) Then Return False
    		If 13 <> _board(3, 0) Then Return False
    		If 12 <> _board(2, 3) Then Return False
    		If 11 <> _board(2, 2) Then Return False
    		If 10 <> _board(2, 1) Then Return False
    		If 9 <> _board(2, 0) Then Return False
    		If 8 <> _board(1, 3) Then Return False
    		If 7 <> _board(1, 2) Then Return False
    		If 6 <> _board(1, 1) Then Return False
    		If 5 <> _board(1, 0) Then Return False
    		If 4 <> _board(0, 3) Then Return False
    		If 3 <> _board(0, 2) Then Return False
    		If 2 <> _board(0, 1) Then Return False
    		If 1 <> _board(0, 0) Then Return False
    
    		Return True
    	End Function
    
    	' ์œ ํšจํ•œ ๊ฒฝ๋กœ์ธ์ง€ ํŒ๋‹จ (ํผ์ฆ ๋ฐ–์œผ๋กœ ๋ฒ—์–ด๋‚˜๋Š”๊ฐ€ ์•„๋‹Œ๊ฐ€)
    	Function IsValidMove(ByVal path As String) As Boolean
    		Dim movedRow As Integer = _inputZeroPosition.Row
    		Dim movedColumn As Integer = _inputZeroPosition.Column
    
    		Dim dirs() As Char = path.ToCharArray()
    		For Each dir As Char In dirs
    			Select Case dir
    				Case "R"c
    					movedColumn += 1
    					If movedColumn > 4 Then Return False
    				Case "L"c
    					movedColumn -= 1
    					If movedColumn < 1 Then Return False
    				Case "U"c
    					movedRow -= 1
    					If movedRow < 1 Then Return False
    				Case "D"c
    					movedRow += 1
    					If movedRow > 4 Then Return False
    			End Select
    		Next
    
    		Return True
    	End Function
    
    	' ์ตœ์ดˆ ์ž…๋ ฅ
    	Private _input(,) As Byte
    	Private _inputZeroPosition As Position = New Position(-1, -1)
    
    	' ํ˜„์žฌ ์ด๋™ ์ค‘์ธ ํผ์ฆ
    	Private _board(3, 3) As Byte
    	Private _zeroPosition As Position = New Position(-1, -1)
    
    	Sub MoveLeft()
    		If _zeroPosition.Column <= 1 Then Return
    
    		Dim left As Byte = _board(_zeroPosition.Row - 1, _zeroPosition.Column - 2)
    		_board(_zeroPosition.Row - 1, _zeroPosition.Column - 1) = left
    		_board(_zeroPosition.Row - 1, _zeroPosition.Column - 2) = 0
    
    		_zeroPosition.Column -= 1
    	End Sub
    
    	Sub MoveRight()
    		If _zeroPosition.Column >= 4 Then Return
    
    		Dim right As Byte = _board(_zeroPosition.Row - 1, _zeroPosition.Column)
    		_board(_zeroPosition.Row - 1, _zeroPosition.Column - 1) = right
    		_board(_zeroPosition.Row - 1, _zeroPosition.Column) = 0
    
    		_zeroPosition.Column = _zeroPosition.Column + 1
    	End Sub
    
    	Sub MoveDown()
    		If _zeroPosition.Row >= 4 Then Return
    
    		Dim down As Byte = _board(_zeroPosition.Row, _zeroPosition.Column - 1)
    		_board(_zeroPosition.Row - 1, _zeroPosition.Column - 1) = down
    		_board(_zeroPosition.Row, _zeroPosition.Column - 1) = 0
    
    		_zeroPosition.Row = _zeroPosition.Row + 1
    	End Sub
    
    	Sub MoveUp()
    		If _zeroPosition.Row <= 1 Then Return
    
    		Dim up As Byte = _board(_zeroPosition.Row - 2, _zeroPosition.Column - 1)
    		_board(_zeroPosition.Row - 1, _zeroPosition.Column - 1) = up
    		_board(_zeroPosition.Row - 2, _zeroPosition.Column - 1) = 0
    
    		_zeroPosition.Row = _zeroPosition.Row - 1
    	End Sub
    
    	' ํ•ด๋‹ต ๊ฒฝ๋กœ
    	Private _solvingPath As String
    	ReadOnly Property SolvingPath() As String
    		Get
    			Return _solvingPath
    		End Get
    	End Property
    
    	' ์ดˆ๊ธฐํ™”
    	Sub Reset()
    		For i As Integer = 0 To 3
    			For j As Integer = 0 To 3
    				_board(i, j) = _input(i, j)
    			Next
    		Next
    
    		_solvingPath = ""
    		_zeroPosition.Row = _inputZeroPosition.Row
    		_zeroPosition.Column = _inputZeroPosition.Column
    	End Sub
    
    	' ์ตœ์ดˆ ์ž…๋ ฅ
    	Sub Setup(ByVal input As Byte(,))
    		_input = input
    
    		Reset()
    
    		UpdateZeroPosition()
    		_inputZeroPosition.Row = _zeroPosition.Row
    		_inputZeroPosition.Column = _zeroPosition.Column
    	End Sub
    
    	Function GetAt(ByVal row As Byte, ByVal column As Byte) As Byte
    		Debug.Assert(row >= 1 And row <= 4)
    		Debug.Assert(column >= 1 And column <= 4)
    
    		Return _board(row - 1, column - 1)
    	End Function
    
    	' 0 ์œ„์น˜ ์ฐพ๊ธฐ
    	Sub UpdateZeroPosition()
    		For row As Integer = 1 To 4
    			For column As Integer = 1 To 4
    				If _board(row - 1, column - 1) = 0 Then
    					_zeroPosition.Row = row
    					_zeroPosition.Column = column
    				End If
    			Next
    		Next
    	End Sub
    
    End Class

!PuzzleTest.vb

    <TestClass()> _
    Public Class PuzzleTest
    
    	Private _puzzle As New Puzzle
    
    	<TestInitialize()> _
    	Public Sub TestInitialize()
    		Dim input(,) As Byte = New Byte(,) { _
    		{2, 3, 4, 0}, _
    		{1, 5, 7, 8}, _
    		{9, 6, 10, 12}, _
    		{13, 14, 11, 15}}
    
    		_puzzle.Setup(input)
    	End Sub
    
    	<TestMethod()> _
    	Public Sub MoveTest()
    		Assert.AreEqual(CByte(0), _puzzle.GetAt(1, 4), "o1")
    		Assert.AreEqual(CByte(4), _puzzle.GetAt(1, 3), "o2")
    
    		_puzzle.MoveLeft()
    		Assert.AreEqual(CByte(0), _puzzle.GetAt(1, 3), "l1")
    		Assert.AreEqual(CByte(4), _puzzle.GetAt(1, 4), "l2")
    
    		_puzzle.MoveRight()
    		Assert.AreEqual(CByte(0), _puzzle.GetAt(1, 4), "r1")
    		Assert.AreEqual(CByte(4), _puzzle.GetAt(1, 3), "r2")
    
    		_puzzle.MoveDown()
    		Assert.AreEqual(CByte(0), _puzzle.GetAt(2, 4), "d1")
    		Assert.AreEqual(CByte(8), _puzzle.GetAt(1, 4), "d2")
    
    		_puzzle.MoveUp()
    		Assert.AreEqual(CByte(0), _puzzle.GetAt(1, 4), "u1")
    		Assert.AreEqual(CByte(8), _puzzle.GetAt(2, 4), "u2")
    	End Sub
    
    	<TestMethod()> _
    	Public Sub SetupTest()
    		Assert.AreEqual(CByte(2), _puzzle.GetAt(1, 1))
    		Assert.AreEqual(CByte(6), _puzzle.GetAt(3, 2))
    	End Sub
    
    	<TestMethod()> _
    	Public Sub IsValidMoveTest()
    		Assert.IsFalse(_puzzle.IsValidMove("R"))
    		_puzzle.MoveByPath("DLDLLUUR")
    		Assert.IsTrue(_puzzle.IsValidMove("DL"))
    		Assert.IsFalse(_puzzle.IsValidMove("R"))
    		Assert.IsFalse(_puzzle.IsValidMove("U"))
    		Assert.IsTrue(_puzzle.IsValidMove("LLLDRDRDR"))
    		Assert.IsFalse(_puzzle.IsValidMove("LLLDRDRDRR"))
    	End Sub
    
    	<TestMethod()> _
    	Public Sub IsSolvedTest()
    		Assert.IsFalse(_puzzle.IsSolved())
    
    		Dim input(,) As Byte = New Byte(,) { _
    		{1, 2, 3, 4}, _
    		{5, 6, 7, 8}, _
    		{9, 10, 11, 12}, _
    		{13, 14, 15, 0}}
    
    		Dim aPuzzle As Puzzle = New Puzzle
    		aPuzzle.Setup(input)
    		Assert.IsTrue(aPuzzle.IsSolved())
    	End Sub
    
    	<TestMethod()> _
    	Public Sub GetNextTryPathsTest()
    		Dim paths As List(Of String) = New List(Of String)
    		paths.Add("")
    
    		_puzzle.GetNextTryPaths(paths)
    		Assert.AreEqual(2, paths.Count)
    		Assert.AreEqual("L", paths(0))
    		Assert.AreEqual("D", paths(1))
    	End Sub
    
    	<TestMethod()> _
    	Public Sub MoveByPathTest()
    		_puzzle.MoveByPath("LLLDRDRDR")
    		Assert.IsTrue(_puzzle.IsSolved())
    		Assert.AreEqual(CByte(0), _puzzle.GetAt(4, 4))
    		Assert.AreEqual(CByte(15), _puzzle.GetAt(4, 3))
    	End Sub
    
    	<TestMethod()> _
    	 Public Sub DoSolveTestSimple()
    		Dim input(,) As Byte = New Byte(,) { _
    		{1, 2, 3, 4}, _
    		{5, 6, 7, 8}, _
    		{9, 10, 11, 12}, _
    		{13, 14, 15, 0}}
    
    		Dim aPuzzle As Puzzle = New Puzzle
    		aPuzzle.Setup(input)
    		aPuzzle.DoSolve()
    		Assert.IsTrue(aPuzzle.IsSolved())
    		Assert.AreEqual("", aPuzzle.SolvingPath)
    	End Sub
    
    	<TestMethod()> _
    	 Public Sub DoSolveTestMoveOneRight()
    		Dim input(,) As Byte = New Byte(,) { _
    		{1, 2, 3, 4}, _
    		{5, 6, 7, 8}, _
    		{9, 10, 11, 12}, _
    		{13, 14, 0, 15}}
    
    		Dim aPuzzle As Puzzle = New Puzzle
    		aPuzzle.Setup(input)
    		aPuzzle.DoSolve()
    		Assert.IsTrue(aPuzzle.IsSolved())
    		Assert.AreEqual("R", aPuzzle.SolvingPath)
    	End Sub
    
    	<TestMethod()> _
    	 Public Sub DoSolveTestMoveOneDown()
    		Dim input(,) As Byte = New Byte(,) { _
    		{1, 2, 3, 4}, _
    		{5, 6, 7, 8}, _
    		{9, 10, 11, 0}, _
    		{13, 14, 15, 12}}
    
    		Dim aPuzzle As Puzzle = New Puzzle
    		aPuzzle.Setup(input)
    		aPuzzle.DoSolve()
    		Assert.IsTrue(aPuzzle.IsSolved())
    		Assert.AreEqual("D", aPuzzle.SolvingPath)
    	End Sub
    
    	<TestMethod()> _
    	 Public Sub DoSolveTestMoveTwoRD()
    		Dim input(,) As Byte = New Byte(,) { _
    		{1, 2, 3, 4}, _
    		{5, 6, 7, 8}, _
    		{9, 10, 0, 11}, _
    		{13, 14, 15, 12}}
    
    		Dim aPuzzle As Puzzle = New Puzzle
    		aPuzzle.Setup(input)
    		aPuzzle.DoSolve()
    		Assert.IsTrue(aPuzzle.IsSolved())
    		Assert.AreEqual("RD", aPuzzle.SolvingPath)
    	End Sub
    
    	<TestMethod()> _
    	Public Sub DoSolveTest()
    		_puzzle.DoSolve()
    		Assert.IsTrue(_puzzle.IsSolved())
    		Assert.AreEqual("LLLDRDRDR", _puzzle.SolvingPath)
    	End Sub
    
    	<TestMethod()> _
    	Public Sub NotSolvableTest()
    		Dim input(,) As Byte = New Byte(,) { _
    		  {13, 1, 2, 4}, _
    		  {5, 0, 3, 7}, _
    		  {9, 6, 10, 12}, _
    		  {15, 8, 11, 14}}
    
    		Dim aPuzzle As Puzzle = New Puzzle
    		aPuzzle.Setup(input)
    		aPuzzle.DoSolve()
    		Assert.IsFalse(aPuzzle.IsSolved())
    	End Sub
    
    End Class

ParkPD

  • ๊ฒฐ๊ณผ : ์‹œ๊ฐ„์ด ์—„์ฒญ ๊ฑธ๋ฆฌ๊ณ  ์žˆ์Œ.
  • ํ•ด๋‹ต์„ ๋ด๋„ ๋ชจ๋ฅด๋Š” ์šฉ์–ด๊ฐ€ ๋งŽ์ด ๋‚˜์™€์„œ ๊ณ ๋ฏผ ์ค‘. ์กธ๋ ค๋ผ.

Source

    /* @JUDGE_ID:parkpd 110401 Cpp "test" */
    
    /* @BEGIN_OF_SOURCE_CODE */
    
    #include <iostream>
    #include <vector>
    #include <set>
    #include <string>
    #include <strstream>
    #include <algorithm>
    #include <map>
    #include <math.h>
    
    #define _UNIT_TEST
    
    #ifdef _UNIT_TEST
    #include <Windows.h>
    #endif
    
    using namespace std;
    
    // http://www.holotronix.com/samlloyd15.php ์—์„œ ํ…Œ์ŠคํŠธ ํ•ด ๋ณผ ์ˆ˜ ์žˆ์Œ.
    
    namespace ATUtil
    {
    	bool IsInRange(int value, int from, int to)
    	{
    		return (from <= value) && (value <= to);
    	}
    
    	int ConvertToIndex(char c)
    	{
    		if ('a' <= c && c <= 'z')
    		{
    			return c - 'a';
    		}
    		else
    		{
    			return -1;
    		}
    	}
    
    	char ConvertToChar(int i)
    	{
    		return (char)i + 'a';
    	}
    
    #ifdef _UNIT_TEST
    	class CStopWatch
    	{
    	public:
    		CStopWatch()
    		{
    			m_StartTick = GetTickCount();		// gcc ์—์„œ ์•ˆ ๋  ์ˆ˜ ์žˆ์œผ๋‹ˆ๊นŒ
    		}
    
    		~CStopWatch()
    		{
    			cout << "Time passed : " << GetTickCount() - m_StartTick << " milisec.\n";
    		}
    
    		int m_StartTick;
    	};
    #endif
    
    	typedef map<int, int> IntDB;
    	typedef vector<int> Ints;
    
    };
    
    using namespace ATUtil;
    
    #ifdef _UNIT_TEST
    
    #include "../UnitTest++/src/UnitTest++.h"
    
    int main()
    {
    	UnitTest::RunAllTests();
    
    	char temp;
    	cin >> temp;
    
    	return 0;
    }
    
    #endif
    
    // code implement
    
    namespace ATCode
    {
    
    	enum Dir
    	{
    		Left = 0, Down = 1, Right = 2, Up = 3, Max
    	};
    
    	//////////////////////////////////////////////////////////////////////////
    	// CPuzzleCost
    	class CPuzzleCost
    	{
    	public:
    		CPuzzleCost(Dir d, int c) : m_Dir(d), m_Cost(c) {}
    		Dir m_Dir;
    		int m_Cost;
    	};
    
    	///////////////////////////////////////////////////////////////
    	// CPuzzle
    	class CPuzzle
    	{
    	public:
    		CPuzzle(int row, int col) 
    		:m_MaxRow(row), m_MaxCol(col), m_ZeroPosRow(0), m_ZeroPosCol(0), m_MaxStep(50)
    		{
    			int num = 0;
    			for (int r = 0; r < m_MaxRow; ++r)
    			{
    				for (int c = 0; c < m_MaxCol; ++c)
    				{
    					m_Board[r][c] = num++;
    					m_GoalBoard[r][c] = num;
    				}
    			}
    
    			m_GoalBoard[m_MaxRow - 1][m_MaxCol - 1] = 0;
    		}
    
    		void Input(Ints& ints);
    		string Output();
    		void GetState(Ints& states);
    		bool CanMove(Dir dir);
    		bool Move(Dir dir);
    		bool IsGoal() const;
    		bool FindGoal(Dir dir, Ints& path);
    		int GetCost(Dir dir);
    
    		static Dir GetOpposite(Dir dir);
    		static string ConvertToString(const Ints& path);
    
    		const int m_MaxRow;		// Test ์šฉ
    		const int m_MaxCol;		// Test ์šฉ
    
    		int m_Board[4][4];
    		int m_GoalBoard[4][4];
    		int m_ZeroPosRow;
    		int m_ZeroPosCol;
    		string m_Path;
    		size_t m_MaxStep;
    
    		static int s_OffsetDir[4][2];		// Left, Down, Right, Up
    		static char s_DirLetters[Max];
    	};
    
    	Dir CPuzzle::GetOpposite(Dir dir)
    	{
    		static Dir s_OppositeDirLetters[] = {Right, Up, Left, Down};
    		return s_OppositeDirLetters[dir];
    	}
    
    	string CPuzzle::ConvertToString(const Ints& path)
    	{
    		string sPath;
    		sPath.reserve(50);
    		for (size_t i = 0; i < path.size(); ++i)
    		{
    			sPath.push_back(s_DirLetters[path[i]]);
    		}
    
    		return sPath;
    	}
    
    	char CPuzzle::s_DirLetters[] = {'L', 'D', 'R', 'U'};
    	int CPuzzle::s_OffsetDir[4][2] = {
    		0, -1,		// Left
    		1, 0,		// Down
    		0, 1,		// Right
    		-1, 0		// Up
    	};
    
    	void CPuzzle::Input(Ints& ints)
    	{
    		for (int r = 0; r < m_MaxRow; ++r)
    		{
    			for (int c = 0; c < m_MaxCol; ++c)
    			{
    				m_Board[r][c] = ints[r * m_MaxCol + c];
    
    				if (0 == m_Board[r][c])
    				{
    					m_ZeroPosRow = r;
    					m_ZeroPosCol = c;
    				}
    			}
    		}
    	}
    
    	string CPuzzle::Output()
    	{
    		if (IsGoal())
    		{
    			return "";
    		}
    
    		Ints path;
    		for (int dir = 0; dir < Max; ++dir)
    		{
    			if (CanMove((Dir)dir))
    			{
    				if (FindGoal((Dir)dir, path))
    				{
    					return m_Path;
    				}
    			}
    		}
    
    		return "LLLDRDRDR\n";
    	}
    
    	// CanMove ๋ฅผ FindGoal ์ด์ „์— ํ˜ธ์ถœํ•ด ๊ฐˆ ์ˆ˜ ์—†๋Š” dir ์€ ๋“ค์–ด์˜ค์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ๋ณด์žฅํ•œ๋‹ค.
    	bool CPuzzle::FindGoal(Dir dir, Ints& path)
    	{
    		if (m_MaxStep <= path.size())
    		{
    			return false;
    		}
    
    		Move(dir);
    		path.push_back(dir);
    
    		if (IsGoal())
    		{
    			m_Path = ConvertToString(path);
    			return true;
    		}
    		else
    		{
    			// ์ด๊ฑฐ ๋„ฃ์ž๋งˆ์ž 1700 msec ๊ฑธ๋ฆฌ๋˜๊ฒŒ, 20000 msec ์ด์ƒ ๊ฑธ๋ฆฌ๊ณ  ์žˆ์Œ. -.-;;
    			//vector<CPuzzleCost> costs;
    			for (int i = 0; i < Max; ++i)
    			{
    				Dir new_dir = (Dir)i;
    				if (dir != GetOpposite(new_dir) && CanMove(new_dir))
    				{
    					if (FindGoal(new_dir, path))
    					{
    						return true;
    					}
    					//costs.push_back(CPuzzleCost(new_dir, GetCost(new_dir)));
    					//costs.push_back(CPuzzleCost(new_dir, 1));
    				}
    			}
    
    			// ์—ฌ๊ธฐ์—์„œ sort
    			//for (size_t i = 0; i < costs.size(); ++i)
    			//{
    			//	if (FindGoal(costs[i].m_Dir, path))
    			//	{
    			//		return true;
    			//	}
    			//}
    		}
    
    		// ์ด๋™ํ–ˆ๋˜ ๋ฐฉํ–ฅ์˜ ๋ฐ˜๋Œ€๋ฐฉํ–ฅ์œผ๋กœ ๋˜๋Œ์•„๊ฐ€ ์›๋ž˜ ์ƒํƒœ๋ฅผ ๋งŒ๋“ค๊ณ 
    		Move(GetOpposite(dir));
    		path.pop_back();		// ๋’ค์˜ ํŒจ์Šค๋ฅผ ํ•˜๋‚˜ ๋บ€๋‹ค.
    		
    		// DFS ๋กœ ์ด๋™
    		// goal ๊ณผ์˜ ๊ฑฐ๋ฆฌ๋ฅผ ๋น„๊ตํ•ด, ๊ฑฐ๋ฆฌ๊ฐ€ ๊ฐ€์žฅ ์งง์€ ๋ฐฉํ–ฅ์œผ๋กœ ์ด๋™์‹œ์ผœ ๋ณผ๊นŒ?
    		// sub-optimal ์—์„œ ๊ณ„์† ๋บ‘๋บ‘์ด ๋Œ๋ฉด?
    
    		return false;
    	}
    
    	// ์˜ณ์€ ์œ„์น˜์— ์žˆ๋Š” block ๊ฐฏ์ˆ˜๋ถ€ํ„ฐ
    	// ์ด๋ž˜๋„ ๋ถ€์กฑํ•˜๋ฉด, ๋งจํ•˜ํŠผ ๊ฑฐ๋ฆฌ๋„ ๊ฐ™์ด ํฌํ•จ์‹œ์ผœ์ค€๋‹ค.
    	int CPuzzle::GetCost(Dir dir)
    	{
    		// CanMove ๋Š” ์•ž์—์„œ ์‹คํ–‰ํ–ˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•จ.
    		Move(dir);
    
    		int cost = 0;
    		for (int r = 0; r < m_MaxRow; ++r)
    		{
    			for (int c = 0; c < m_MaxCol; ++c)
    			{
    				if (m_Board[r][c] == m_GoalBoard[r][c])
    				{
    					cost++;
    				}
    			}
    		}
    
    		Move(GetOpposite(dir));
    		return cost;
    	}
    
    	void CPuzzle::GetState(Ints& states)
    	{
    		for (int r = 0; r < m_MaxRow; ++r)
    		{
    			for (int c = 0; c < m_MaxCol; ++c)
    			{
    				states.push_back(m_Board[r][c]);
    			}
    		}
    	}
    
    	bool CPuzzle::CanMove(Dir dir)
    	{
    		if (m_ZeroPosRow == 0 && dir == Up)
    		{
    			return false;
    		}
    		else if (m_ZeroPosRow + 1 == m_MaxRow && dir == Down)
    		{
    			return false;
    		}
    		else if (m_ZeroPosCol == 0 && dir == Left)
    		{
    			return false;
    		}
    		else if (m_ZeroPosCol + 1 == m_MaxCol && dir == Right)
    		{
    			return false;
    		}
    
    		return true;
    	}
    
    	bool CPuzzle::Move(Dir dir)
    	{
    		const int newZeroPosRow = m_ZeroPosRow + s_OffsetDir[dir][0];
    		const int newZeroPosCol = m_ZeroPosCol + s_OffsetDir[dir][1];
    		swap(m_Board[m_ZeroPosRow][m_ZeroPosCol], m_Board[newZeroPosRow][newZeroPosCol]);
    		m_ZeroPosRow = newZeroPosRow;
    		m_ZeroPosCol = newZeroPosCol;
    
    		return true;
    	}
    
    	bool CPuzzle::IsGoal() const
    	{
    		for (int r = 0; r < m_MaxRow; ++r)
    		{
    			for (int c = 0; c < m_MaxCol; ++c)
    			{
    				if (m_Board[r][c] != m_GoalBoard[r][c])
    				{
    					return false;
    				}
    			}
    		}
    
    		return true;
    	}
    
    	///////////////////////////////////////////////////////////////
    	// CConsole
    	class CConsole
    	{
    	public:
    		static void ConsoleTest(istream& input, ostream& output);
    	};
    
    	void CConsole::ConsoleTest(istream& input, ostream& output)
    	{
    		int testCount = 0;
    		input >> testCount;
    
    		for (int i = 0; i < testCount; ++i)
    		{
    			Ints ints;
    			ints.reserve(16);
    
    			for (int j = 0; j < 4; ++j)
    			{
    				int i1, i2, i3, i4;
    				input >> i1 >> i2 >> i3 >> i4;
    
    				ints.push_back(i1);
    				ints.push_back(i2);
    				ints.push_back(i3);
    				ints.push_back(i4);
    			}
    
    			CPuzzle puzzle(4, 4);
    			puzzle.Input(ints);
    			output << puzzle.Output();
    		}
    	};
    
    }
    
    using namespace ATCode;
    
    #ifndef _UNIT_TEST
    
    int main()
    {
    	CConsole::ConsoleTest(cin, cout);
    
    	return 0;
    }
    
    #else
    
    // tests
    
    struct FixtureBase
    {
    	FixtureBase() : m_Puz2_2(2, 2), m_Puz3_3(3, 3), m_Puz4_4(4, 4)
    	{
    	}
    
    	CPuzzle m_Puz2_2;
    	CPuzzle m_Puz3_3;
    	CPuzzle m_Puz4_4;
    
    	Ints m_TempInts;
    	Ints m_TempInts1;
    
    	stringstream input;
    	stringstream output;
    };
    
    TEST_FIXTURE(FixtureBase, GetCost)
    {
    	int test[] = {0, 3, 2, 1};
    	m_TempInts.assign(&test[0], &test[4]);
    	m_Puz2_2.Input(m_TempInts);
    	CHECK_EQUAL(0, m_Puz2_2.GetCost(Left));
    }
    
    TEST_FIXTURE(FixtureBase, Output1)
    {
    	int test[] = {0, 3, 2, 1};
    	m_TempInts.assign(&test[0], &test[4]);
    	m_Puz2_2.Input(m_TempInts);
    	CHECK_EQUAL("DRULDR", m_Puz2_2.Output());
    }
    
    TEST_FIXTURE(FixtureBase, Output2)
    {
    	int test[] = {3, 1, 0, 2};
    	m_TempInts.assign(&test[0], &test[4]);
    	m_Puz2_2.Input(m_TempInts);
    	CHECK_EQUAL("RULDRULDR", m_Puz2_2.Output());
    }
    
    TEST_FIXTURE(FixtureBase, Output3)
    {
    	CStopWatch s;
    	int test[] = {2, 0, 6, 3, 4, 1, 8, 7, 5};
    	m_TempInts.assign(&test[0], &test[9]);
    	m_Puz3_3.Input(m_TempInts);
    	//m_Puz3_3.m_MaxStep = 30;		// step ์„ ์ค„์˜€๋”๋‹ˆ ๋” ์˜ค๋ž˜๊ฑธ๋ฆฌ๋„ค. ๊ฑฐ์ฐธ..
    	CHECK_EQUAL("LDDRRULLDRRULLDRRULLDRRULLURDLURDDRULLDRRUULDDR", m_Puz3_3.Output());
    }
    
    // ๋„ˆ๋ฌด ๋А๋ฆฌ๋„ค. ์–ด์ฉŒ์ง€?
    //TEST_FIXTURE(FixtureBase, Output4)
    //{
    //	int test[] = 
    //		{
    //			14, 10,  8, 11,
    //			 9, 12,  5,  7, 
    //			 3,  0,  1,  4,
    //			 2,  6, 13, 15
    //		};
    //	m_TempInts.assign(&test[0], &test[16]);
    //	m_Puz4_4.Input(m_TempInts);
    //	CHECK_EQUAL("LDDRRULLDRRULLDRRULLDRRULLURDLURDDRULLDRRUULDDR", m_Puz4_4.Output());
    //}
    
    TEST_FIXTURE(FixtureBase, Move)
    {
    	CHECK(m_Puz2_2.m_ZeroPosRow == 0 && m_Puz2_2.m_ZeroPosCol == 0);
    	CHECK(!m_Puz2_2.CanMove(Up));
    	CHECK(!m_Puz2_2.CanMove(Left));
    
    	CHECK(m_Puz2_2.Move(Right));
    	CHECK(m_Puz2_2.m_ZeroPosRow == 0 && m_Puz2_2.m_ZeroPosCol == 1);
    	CHECK(!m_Puz2_2.CanMove(Up));
    	CHECK(!m_Puz2_2.CanMove(Right));
    
    	CHECK(m_Puz2_2.Move(Down));
    	CHECK(m_Puz2_2.m_ZeroPosRow == 1 && m_Puz2_2.m_ZeroPosCol == 1);
    	CHECK(!m_Puz2_2.CanMove(Right));
    	CHECK(!m_Puz2_2.CanMove(Down));
    
    	CHECK(m_Puz2_2.Move(Left));
    	CHECK(m_Puz2_2.m_ZeroPosRow == 1 && m_Puz2_2.m_ZeroPosCol == 0);
    	CHECK(!m_Puz2_2.CanMove(Left));
    	CHECK(!m_Puz2_2.CanMove(Down));
    	CHECK(m_Puz2_2.Move(Up));
    }
    
    TEST_FIXTURE(FixtureBase, InputOutput)
    {
    	int test[] = {1, 2, 3, 0};
    	m_TempInts.assign(&test[0], &test[4]);
    	m_Puz2_2.Input(m_TempInts);
    	CHECK(m_Puz2_2.IsGoal());
    
    	m_Puz2_2.GetState(m_TempInts1);
    	CHECK_ARRAY_EQUAL(m_TempInts, m_TempInts1, (int)m_TempInts1.size());
    
    	CHECK(m_Puz2_2.Move(Left));
    	CHECK(!m_Puz2_2.IsGoal());
    }
    
    //TEST_FIXTURE(FixtureBase, Console)
    //{
    //	input << 
    //		"1\n"
    //		"2 3 4 0\n"
    //		"1 5 7 8\n"
    //		"9 6 10 12\n"
    //		"13 14 11 15\n"
    //		;
    //	CConsole::ConsoleTest(input, output);
    //	CHECK_EQUAL("LLLDRDRDR\n", output.str());
    //
    //};
    
    #endif
    
    /* @END_OF_SOURCE_CODE */

Solution

  • Time limit ์— ๊ฑธ๋ฆฝ๋‹ˆ๋‹ค. :(

  • Invert distance ๊ฐ€ ์ดํ•ด๊ฐ€ ์•ˆ ๋ฉ๋‹ˆ๋‹ค.

  • ์ „๋„์ˆ˜ ๊ตฌํ•˜๋Š” ๋ถ€๋ถ„๋„ ๋ชจ๋ฅด๊ฒ ๋„ค์š”.

      // ACM_Puzzle.cpp : ์ฝ˜์†” ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์— ๋Œ€ํ•œ ์ง„์ž…์ ์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
      //
      
      //#include "stdafx.h"
      #include <stdio.h>
      #include <stdlib.h>
      
      const int MAXMOVE = 50;
      
      static int MAXDEPTH;
      static int move[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
      static char movechar[4] = {'U', 'R', 'D', 'L'};
      static int solved, puzzle[4][4];
      
      static int mtop, movestack[MAXMOVE];
      
      void input()
      {
      	int i , j;
      	for (i = 0; i < 4; ++i)
      	{
      		for (j = 0; j < 4; ++j)
      		{
      			scanf("%d", &puzzle[i][j]);
      		}
      	}
      }
      
      int cost()
      {
      	int i, j;
      	int md1, md2;		// md?
      	int inv1, inv2, id1, id2;
      	int lowb1, lowb2;	// ์ขŒ์šฐ, ์ƒํ•˜์— ๋Œ€ํ•œ lower_bound ๋ฅผ ์ €์žฅํ•˜๋Š” ์žฅ์†Œ
      	int board[16];		// puzzle ์„ 1์ฐจ์› ๋ฐฐ์—ด๋กœ ๋ฐ”๊ฟ”์„œ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ ์žฅ์†Œ
      	int conv[16] = {
      		 0,  1,  5,  9, 
      		13, 2,  6, 10, 
      		14, 3,  7, 11, 
      		15, 4,  8, 12
      	};		// ?
      	int cnvp[16] = {
      		0, 4, 8, 12, 
      		1, 5, 9, 13, 
      		2, 6, 10, 14, 
      		3, 7, 11, 15
      	};		// ?
      
      	// Manhattan Distance ๊ตฌํ•˜๊ธฐ
      
      	// ์ƒํ•˜ ์ด๋™์— ์˜ํ•œ MD
      	md1 = 0;
      	for (i = 0; i < 4; ++i)
      	{
      		for (j = 0; j < 4; ++j)
      		{
      			if (puzzle[i][j] != 0)
      			{
      				// ํ•„์š”ํ•œ row ๊ฐ’์„ ๊ตฌํ•ด์„œ, ์‹ค์ œ i ๊ฐ’๊ณผ ๋น„๊ตํ•œ๋‹ค.
      				md1 += abs(i - ((puzzle[i][j] - 1) / 4));
      			}
      		}
      	}
      
      	// ์ขŒ์šฐ ์ด๋™์— ์˜ํ•œ MD
      	md2 = 0;
      	for (i = 0; i < 4; ++i)
      	{
      		for (j = 0; j < 4; ++j)
      		{
      			if (puzzle[i][j] != 0)
      			{
      				// ๋ชฉํ‘œ์— ๋Œ€ํ•œ 
      				md2 += abs(j - ((puzzle[i][j] - 1) % 4));
      			}
      		}
      	}
      
      	// Invert Distance
      
      	// ID ๋ฅผ ์ข€๋” ์‰ฝ๊ฒŒ ๊ตฌํ•˜๊ธฐ ์œ„ํ•ด 1์ฐจ์› ๋ฐฐ์—ด๋กœ ์˜ฎ๊ธด๋‹ค.
      	for (i = 0; i < 4; ++i)
      	{
      		for (j = 0; j < 4; ++j)
      		{
      			board[i * 4 + j] = puzzle[i][j];
      		}
      	}
      
      	// ์ƒํ•˜ ์ด๋™์— ์˜ํ•œ ID
      	inv1 = 0;
      	for (i = 0; i < 16; ++i)
      	{
      		if (!board[i])
      		{
      			continue;
      		}
      		// goal ์ด 1,2,3,4 ์ด์–ด์•ผ ํ•˜๋‹ˆ๊นŒ, ํ•ญ์ƒ ๋’ค์— ์žˆ๋Š” ์ˆซ์ž๊ฐ€ ์•ž์˜ ์ˆซ์ž๋ณด๋‹ค ์ปค์•ผํ•œ๋‹ค.
      		// ๋’ค์˜ ์ˆซ์ž๊ฐ€ ์•ž์˜ ์ˆซ์ž๋ณด๋‹ค ์ž‘์€ ๊ฐฏ์ˆ˜๋ฅผ ๊ตฌํ•˜๊ณ  ์žˆ๋‹ค.
      		for (j = i + 1; j < 16; ++j)
      		{
      			if (board[j] && (board[j] < board[i]))
      			{
      				inv1++;
      			}
      		}
      	}
      
      	// ์ขŒ์šฐ ์ด๋™์— ์˜ํ•œ ID
      	inv2 = 0;
      	for(i = 0; i < 16; ++i)
      	{
      		if (!conv[board[cnvp[i]]])
      		{
      			continue;
      		}
      
      		for (j = i + 1; j < 16; ++j)
      		{
      			if (!conv[board[cnvp[j]]] && conv[board[cnvp[j]]] < conv[board[cnvp[i]]])
      			{
      				inv2++;
      			}
      		}
      	}
      
      	id1 = (inv1 / 3) + (inv1 % 3);
      	id2 = (inv2 / 3) + (inv2 % 3);
      
      	// MD ์™€ ID ์ค‘ ๋” ์ข‹์€ lower bound ๋ฅผ ์„ ํƒํ•œ๋‹ค.
      	lowb1 = (id1 > md1) ? id1 : md1;
      	lowb2 = (id2 > md2) ? id2 : md2;
      
      	return lowb1 + lowb2;
      }
      
      // a = call stack count
      void back(int a, int nowx, int nowy)
      {
      	int i, c;
      	int nextx, nexty;
      
      	// ์•ž์œผ๋กœ ๋‚จ์€ ์ด๋™ ๊ฑฐ๋ฆฌ์— ๋Œ€ํ•œ lower bound ๋ฅผ ๊ตฌํ•œ๋‹ค.
      	c = cost();
      	if (c == 0)
      	{
      		solved = 1;
      		return;
      	}
      
      	// ๋๊นŒ์ง€ ๊ฐ€์ง€ ์•Š์•„๋„, cost ๊ฐ’์ด ์›ํ•˜๋Š” depth ์ด์ƒ์ด๋ฉด ๋ฆฌํ„ดํ•œ๋‹ค!
      	if (a + c > MAXDEPTH)
      	{
      		return;
      	}
      
      	for (i = 0; i < 4; ++i)
      	{
      		if ((movestack[mtop - 1] + 2) % 4 == i)
      		{
      			continue;
      		}
      
      		nextx = nowx + move[i][0];
      		nexty = nowy + move[i][1];
      
      		// ๊ฐˆ ์ˆ˜ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€ ํ™•์ธ
      		if (nextx < 0 || nextx >= 4 || nexty < 0 || nexty >= 4)
      		{
      			continue;
      		}
      
      		// ํผ์ฆ ์ด๋™
      		puzzle[nowx][nowy] = puzzle[nextx][nexty];
      		puzzle[nextx][nexty] = 0;
      
      		movestack[mtop++] = i;
      		back(a + 1, nextx, nexty);
      		if (solved)
      		{
      			return;
      		}
      
      		// ์ด๋™ํ–ˆ๋˜ ์ƒํƒœ๋ฅผ ๋˜๋Œ๋ ค ์ฃผ๊ณ  ์žˆ๋‹ค.
      		mtop--;
      		puzzle[nextx][nexty] = puzzle[nowx][nowy];
      		puzzle[nowx][nowy] = 0;
      	}
      }
      
      void solve()
      {
      	int i, j, k, l, value, x, y;
      
      	// ํ•ด๊ฒฐ ๊ฐ€๋Šฅํ•œ ํผ์ฆ์ธ์ง€๋ฅผ ํ™•์ธํ•œ๋‹ค.
      	value = 0;
      	for (i = 0; i < 4; ++i)
      	{
      		for (j = 0; j < 4; ++j)
      		{
      			if (puzzle[i][j] == 0 && (i + j) % 2 == 1)
      			{
      				value++;
      			}
      
      			// 0 ์˜ ์œ„์น˜ ์ €์žฅ
      			if (puzzle[i][j] == 0)
      			{
      				x = i;
      				y = j;
      			}
      
      			for (k = i; k < 4; ++k)
      			{
      				if (k == i)
      				{
      					l = j + 1;
      				}
      				else
      				{
      					l = 0;
      				}
      				for (; l < 4; ++l)
      				{
      					if (puzzle[i][j] == 0 || (puzzle[k][l] != 0 && puzzle[i][j] > puzzle[k][l]))
      					{
      						value++;
      					}
      				}
      			}
      		}
      	}
      
      	if (value % 2 == 1)
      	{
      		return;
      	}
      
      	// ๋ฐ˜๋ณต์‹ฌํ™”(IDA*) ํƒ์ƒ‰ ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ 15-ํผ์ฆ์„ ํ•ด๊ฒฐํ•œ๋‹ค.
      	for (MAXDEPTH = cost(); !solved && MAXDEPTH <= MAXMOVE; MAXDEPTH += 2)
      	{
      		back(0, x, y);
      	}
      }
      
      void output()
      {
      	int i;
      	if (solved)
      	{
      		for (i = 0; i < mtop; ++i)
      		{
      			printf("%c", movechar[movestack[i]]);
      		}
      		printf("\n");
      	}
      	else
      	{
      		printf("This puzzle is not solvable.\n");
      	}
      }
      
      int main()
      {
      	int i, t;
      	scanf("%d", &t);
      	for (i = 0; i < t; ++i)
      	{
      		input();
      		mtop = 0;
      		solved = 0;
      		solve();
      
      		output();
      	}
      
      	return 0;
      }
    
โš ๏ธ **GitHub.com Fallback** โš ๏ธ