UVa Problem 10181 15-Puzzle Problem(15デジタルゲーム)


// 15-Puzzle Problem (15     )
// PC/UVa IDs: 110802/10181, Popularity: B, Success rate: average Level: 3
// Verdict: Accepted 
// Submission Date: 2011-06-22
// UVa Run Time: 0.320s
//
//     (C)2011,  。metaphysis # yeah dot net
//
// You can fool some of the people all of the time, and all of the people
// some of the time, but you can not fool all of the people all of the time.
//      Abraham Lincoln, 16th president of US (1809 - 1865).
//
//                       http://mathworld.wolfram.com/15Puzzle.html 。
//   e          ,n                        ,N  :
//
//       15        15
// N =   ∑  ni =   ∑  ni
//     i = 1     i = 2
//
//    N + e    ,       ,    。     :
//
// 13 10 11 6
// 5  7  4  8
// 1  12 14 9 
// 3  15 2  0 
//
//      13              12,   10              9,   ,    
//       n      9(11),5(6),4(5),4(7),3(4),3(8),0(1),3(12),
// 3(14),2(9),1(3),1(15),0(2)。   n      N = 59,      4  ,  e =
// 4,  N + e = 63,   ,        。
//
// [        (Depth-First Search)]
// [   George T. Heineman, Gary Pollice, and Stanley Selkow, ALGORITHMS In a 
// Nutshell, O‘Reilly Media, Inc. 2008]
//
//                  ,               ,            ,
//                 ,                             ,
//            ,           。      ,                
//      ,             ,             。           , 
//    。        ,                  。               ,
//       。     :
//
// search (initial, goal)
//      if (initial = goal) then return "Solution"
//      initial.depth = 0
//      open = new Stack
//      closed = new Set
//      insert(open, copy(initial))
//      while (open is not empty) do
//              n = pop(open)
//              insert(closed, n)
//              foreach valid move m at n do
//                      next = state when playing m at n
//                      if (closed doesn't contain next) then
//                              next.depth = n.depth + 1
//                              if (next = goal) then return "Solution"
//                              if (next.depth < maxDepth) then
//                                      insert(open, next)
//      return "No Solution"
// end
//
//               ,                  45      ,       
//   50  ,          50。                         ,    
//                                ,               
//      ,    ,               ,             ,      
//        ,    。                       ,       ,  
//                 ,                    ,         
//         ,                       ,        ,     
//         。
//
//        ,                 。            16      ,  
//             ,     ,                16    ,       
//               :
//
// 13 * 16^15 + 10 * 16^14 + 11 * 16^13 + 6 * 16^12 + 5 * 16^11 + 7 * 16^10 + 
// 4 * 16^9 + 8 * 16^8 + 1 * 16^7 + 12 * 16^6 + 14 * 16^5 + 9 * 16^4 + 
// 3 * 16^3 + 15 * 16^2 + 2 * 16^1 + 0 * 16^1 = DAB657481CE93F20(hex) = 
// 15759879913263939360(dec)
//
//                           。
//
// [        (Breadth-First Search)]
//
//                     ,        。                 
//      ,            。                            
//         ,          。     ,                    ,
//          ,      ,         ,      ,             
//      。                     ,      。     :
//
// search (initial, goal)
//      if (initial = goal) then return "Solution"
//      open = new Queue
//      closed = new Set
//      insert(open, copy(initial))
//      while (open is not empty) do
//              n = head(open)
//              insert(closed, n)
//              foreach valid move m at n do
//                      next = state when playing m at n
//                      if (closed doesn't contain next) then
//                              if (next = goal) then return "Solution"
//                              insert(open, next)
//      return "No Solution"
// end
//
// [A*     ]
// [   George T. Heineman, Gary Pollice, and Stanley Selkow, ALGORITHMS In a 
// Nutshell, O‘Reilly Media, Inc. 2008]
//
//                (    ),             ,           
//     ,  ,                 ,  ,                 ,
//                           。A*                ,  
//        。A*            ,              。      ,A*  
//           f*(n)              ,         。  :
//
// f*(n) = g*(n) + h*(n)
// g*(n)            n        。
// h*(n)       n             。
// f*(n)          ,     n,             。
//
//    *           (  1968        ,         ),   f*(n),
// g*(n),h*(n)        f(n),g(n),h(n)   ,                
//    。f*(n)   ,     n        。f*(n)              h*(n),
//    g*(n)          ,       n        。   h*(n)        
//                     ,   A*                 。     
//      h*(n),     f*(n)              。     :
//
// search (initial, goal)
//      initial.depth = 0
//      open = new PriorityQueue
//      closed = new Set
//      insert(open, copy(initial))
//      while (open is not empty) do
//              n = minimum(open)
//              insert(closed, n)
//              if (n = goal) then return "Solution"
//              foreach valid move m at n do
//                      next = state when playing m at n
//                      next.depth = n.depth + 1
//                      if (closed contains next) then
//                              prior = state in closed matching next
//                              if (next.score < prior.score) then
//                                      remove(closed, prior)
//                                      insert(open, next)
//                      else
//                              insert(open, next)
//      return "No Solution"
// end
//
// [     A*(Iterative-Deepening A* Search,IDA*)    ]
// [   Richard E. Korf, "Recent Progress in the Design and Analysis of Admissible
// Heuristic Functions," Proceeding, Abstraction, Reformulation, and Approximation:
// 4th International Symposium (SARA), Lecture notes in Computer Science #1864:
// 45 - 51, 2000]
//
// IDA*                      。        ,             
//     。IDA*                       ,                
//                  。
	
#include <iostream>
#include <cstring>
#include <limits>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
	
using namespace std;
	
#define SQUARES 4		//        。
#define BASE 16			//            。
#define DEPTHBOUND 30		//                 。
#define STEPSBOUND 50		//       。
	
#define MOVE_LEFT (-1)
#define MOVE_RIGHT 1
#define MOVE_UP (-SQUARES)
#define MOVE_DOWN SQUARES
#define MOVE_NONE 0
	
int manhattan[SQUARES * SQUARES][SQUARES * SQUARES];	//            。
int move[SQUARES];	//     。
	
//                。
struct node
{
	vector < int > state;		//         。
	int moves[STEPSBOUND];		//                。
	int depth;			//     。
	int score;			//        。
	int blank;			//     。
};
	
//          。             。
bool operator<(node x, node y)
{
	return x.score > y.score;
}
	
//     。
int absi(int x)
{
	return x >= 0 ? x : (-x);
}
	
//           。
bool solvable(vector < int > tiles)
{
	int sum = 0, row;
	for (int i = 0; i < tiles.size(); i++)
	{
		int tile = tiles[i];
		if (tile == 0)
		{
			row = (i / SQUARES + 1);
			continue;
		}

		for (int m = i; m < tiles.size(); m++)
			if (tiles[m] < tile && tiles[m] != 0)
				sum++;
	}
	
	return !((sum + row) % 2);
}
	
//            。MOVE_LEFT =        ,MOVE_RIGHT =        ,
// MOVE_UP =        ,MOVE_DOWN =        。
void valid_moves(node &current)
{
	//       ,                。
	int last_move = MOVE_NONE;
	if (current.depth)
		last_move = current.moves[current.depth - 1];
	
	memset(move, MOVE_NONE, sizeof(move));
	if (current.blank % SQUARES > 0 && last_move != MOVE_RIGHT)
		move[0] = MOVE_LEFT;;
	if (current.blank % SQUARES < (SQUARES - 1) && last_move != MOVE_LEFT)
		move[1] = MOVE_RIGHT;
	if (current.blank / SQUARES > 0 && last_move != MOVE_DOWN)
		move[2] = MOVE_UP;
	if (current.blank / SQUARES < (SQUARES - 1) && last_move != MOVE_UP)
		move[3] = MOVE_DOWN;
}
	
//             。
unsigned long long key(vector < int > &tiles)
{
	unsigned long long key = 0;
	for (int i = 0; i < tiles.size(); i++)
		key = key * BASE + tiles[i];
	return key;
}
	
//     current    move       。
node execute(node &current, int move)
{
	node successor;
	
	//       。
	memcpy(successor.moves, current.moves, sizeof(current.moves));
	successor.depth = current.depth + 1;
	successor.moves[current.depth] = move;
	
	//       。  move       ,       。
	successor.state = current.state;
	successor.blank = current.blank + move;
	successor.state[current.blank] = successor.state[successor.blank];
	successor.state[successor.blank] = 0;
	
	return successor;
}

//    h*(n)         ,         ,          ,          
//   h*(n)         ,                         ,      
//                     。g*(n)          ,           
//  : f*(n) = g*(n) + 4 / 3 * h*(n),h*(n)                 ,  
//             。        ,            ,            
//      。   :
// [Bernard Bauer,The Manhattan Pair Distance Heuristic for the 15-Puzzle,1994]
int score(vector < int > &state, int depth)
{
	int hn = 0;
	
	for (int i = 0; i < state.size(); i++)
		if (state[i] > 0)
			hn += manhattan[state[i] - 1][i];
	
	return (depth + 4 * hn / 3);
}
	
//            。
bool solved(vector < int > &state)
{
	if (state[SQUARES * SQUARES - 1] != 0)
		return false;
	
	for (int i = 0; i < SQUARES * SQUARES - 1; i++)
		if (state[i] != (i + 1))
			return false;
	
	return true;
}
	
//             。
int find_blank(vector < int > &state)
{
	for (int i = 0; i < SQUARES * SQUARES; i++)
		if (state[i] == 0)
			return i;
}
	
// [      ]
//                     。        (15   )         ,  
//           ,                  ,        ,        
//  。               ,          ,       ,   ,      
//      。
bool solve_puzzle_by_depth_first_search(vector < int > tiles, int directions[])
{
	node copy;
	copy.state = tiles;
	copy.depth = 0;
	copy.blank = find_blank(tiles);
	memset(copy.moves, MOVE_NONE, sizeof(copy.moves));
	
	//               。
	if (solved(copy.state))
	{
		memcpy(directions, copy.moves, sizeof(copy.moves));
		return true;
	}
	
	//            。
	stack < node > open;	//                。
	open.push(copy);
	
	//    。
	set < unsigned long long > closed;
	while (!open.empty())
	{
		//          ,           。
		node current = open.top();
		open.pop();
		closed.insert(key(current.state));
	
		//           ,            。
		valid_moves(current);
		for (int i = 0; i < SQUARES; i++)
		{
			if (move[i] == MOVE_NONE)
				continue;
	
			//           。
			node successor = execute(current, move[i]);
			
			//       ,        。
			if (closed.find(key(successor.state)) != closed.end())
				continue;
	
			//           ,     ,      。        
			//           。    
			if (solved(successor.state))
			{
				memcpy(directions, successor.moves, 
					sizeof(successor.moves));
				return true;
			}
	
			//            。
			if (successor.depth < DEPTHBOUND)
				open.push(successor);
		}
	}
	
	return false;
}
	
// [      ]
//         (15   )         ,            ,          
//         ,        ,         。
bool solve_puzzle_by_breadth_first_search(vector < int > tiles, int directions[])
{
	node copy;
	copy.state = tiles;
	copy.depth = 0;
	copy.blank = find_blank(tiles);
	memset(copy.moves, MOVE_NONE, sizeof(copy.moves));
	
	//               。
	if (solved(copy.state))
	{
		memcpy(directions, copy.moves, sizeof(copy.moves));
		return true;
	}
	
	//            。
	queue < node > open;	//                。
	open.push(copy);
	
	//    。
	set < unsigned long long > closed;
	while (!open.empty())
	{
		//          ,           。
		node current = open.front();	//       。
		open.pop();
		closed.insert(key(current.state));
	
		//           ,            。
		valid_moves(current);
		for (int i = 0; i < SQUARES; i++)
		{
			if (move[i] == MOVE_NONE)
				continue;
	
			//           。
			node successor = execute(current, move[i]);
	
			//       ,        。
			if (closed.find(key(successor.state)) != closed.end())
				continue;
	
			//           ,     ,      。   
			if (solved(successor.state))
			{
				memcpy(directions, successor.moves, 
					sizeof(successor.moves));
				return true;
			}
	
			//            。
			open.push(successor);
		}
	}
	
	return false;
}
	
// [A*   ]
//                     ,            ,            ,
// A*             ,           (              ),    
//      ,                        ,         DFS   BFS  
//  ,          ,            A*       ,      ,      
//     ,           。         ,                    
//          ,           ,           ,    A*         
//   ,      ,                         。
bool solve_puzzle_by_a_star(vector < int > tiles, int directions[])
{
	node copy;
	copy.state = tiles;
	copy.depth = 0;
	copy.blank = find_blank(tiles);
	copy.score = score(copy.state, 0);
	memset(copy.moves, MOVE_NONE, sizeof(copy.moves));
	
	priority_queue < node > open;	// A*              。
	open.push(copy);
	
	map < unsigned long long, int > closed;
	while (!open.empty())
	{
		//           ,       。
		node current = open.top();
		open.pop();
		
		//                  。
		closed.insert(make_pair< unsigned long long, int >
			(key(current.state), current.score));
		
		//        ,  。
		if (solved(current.state))
		{
			memcpy(directions, current.moves, 
				sizeof(current.moves));
			return true;
		}
			
		//       ,         。
		valid_moves(current);
		for (int i = 0; i < SQUARES; i++)
		{
			if (move[i] == MOVE_NONE)
				continue;
	
			//     ,      。
			node successor = execute(current, move[i]);
			
			//               。
			successor.score = score(successor.state, successor.depth);
			
			//            ,                 ,   
			//  ,  ,            。        ,      
			//                 ,            ,   
			//  ,                  ,            
			//   ,           “  ”  。
			map <  unsigned long long, int >::iterator it = 
				closed.find(key(successor.state));

			if (it != closed.end())
			{
				if (successor.score >= (*it).second)
					continue;
				closed.erase(it);
			}
	
			//            。
			open.push(successor);
		}
	}
	
	return false;
}
	
// [IDA*   ]
//               ,        ,        ,A*       ,     
//          ,      。IDA*           。IDA*              
//                    。
bool solve_puzzle_by_iterative_deepening_a_star(vector < int > tiles,
        int directions[])
{
	node copy;
	copy.state = tiles;
	copy.depth = 0;
	copy.blank = find_blank(tiles);
	memset(copy.moves, MOVE_NONE, sizeof(copy.moves));
	
	//               。
	if (solved(copy.state))
	{
		memcpy(directions, copy.moves, sizeof(copy.moves));
		return true;
	}
	
	//                 。
	int depth_limit = 0, min_depth = score(copy.state, 0);
	
	while (true)
	{
		//         。
		if (depth_limit < min_depth)
			depth_limit = min_depth;
		else
			depth_limit++;
	
		numeric_limits< int > t;
		min_depth = t.max();
	
		//           ,    depth_limit。
		stack < node > open;
		open.push(copy);
		while (!open.empty())
		{
			node current = open.top();
			open.pop();
			
			//           ,            。
			valid_moves(current);
			for (int i = 0; i < SQUARES; i++)
			{
				if (move[i] == MOVE_NONE)
					continue;
	
				//           。
				node successor = execute(current, move[i]);
	
				//           ,     ,      。   
				//                。    
				if (solved(successor.state))
				{
					memcpy(directions, successor.moves, 
						sizeof(successor.moves));
					return true;
				}
	
				//          ,     ,    ,      
				//    。
				successor.score = score(successor.state, 
					successor.depth);
	
				if (successor.score < depth_limit)
					open.push(successor);
				else
				{
					if (successor.score < min_depth)
						min_depth = successor.score;
				}
			}			
		}
	}
	
	return false;
}
	
void solve_puzzle(vector < int > tiles)
{
	int moves[STEPSBOUND];
	
	//       。
	// solve_puzzle_by_depth_first_search(tiles, moves);
	
	//       。
	// solve_puzzle_by_breadth_first_search(tiles, moves);
	
	// A*   。     30 - 50            7 s。UVa RT 1.004 s。
	// solve_puzzle_by_a_star(tiles, moves);
	
	// IDA*   。     30 - 50            1.5 s。UVa RT 0.320 s。
	solve_puzzle_by_iterative_deepening_a_star(tiles, moves);
	
	//       。
	for (int i = 0; i < STEPSBOUND; i++)
	{
		if (moves[i] == MOVE_NONE)
			break;
	
		switch (moves[i])
		{
			case MOVE_LEFT:
				cout << "L";
				break;
			case MOVE_RIGHT:
				cout << "R";
				break;
			case MOVE_UP:
				cout << "U";
				break;
			case MOVE_DOWN:
				cout << "D";
				break;
		}
	}
	
	cout << endl;
}
	
//            。
void cal_manhattan(void)
{
	for (int i = 0; i < SQUARES * SQUARES; i++)
		for (int j = 0; j < SQUARES * SQUARES; j++)
		{
			int tmp = 0;
			tmp += (absi(i / SQUARES - j / SQUARES) + 
				absi(i % SQUARES - j % SQUARES));
			manhattan[i][j] = tmp;
		}	
}
	
int main(int ac, char *av[])
{	
	//        ,  。
	cal_manhattan();
	
	int n, tile;
	vector < int > tiles;	//         。
	
	cin >> n;
	
	while (n--)
	{
		//       。
		tiles.clear();
		for (int i = 0; i < SQUARES * SQUARES; i++)
		{
			cin >> tile;
			tiles.push_back(tile);
		}

		//       ,         ,           。
		if (solvable(tiles))
			solve_puzzle(tiles);
		else
			cout << "This puzzle is not solvable." << endl;
	}
	
	return 0;
}