PKU1077 Eight
Description
The 15-puzzle has been around for over 100 years; even if you don't know it by that name, you've seen it. It is constructed with 15 sliding tiles, each with a number from 1 to 15 on it, and all packed into a 4 by 4 frame with one tile missing. Let's call the missing tile 'x'; the object of the puzzle is to arrange the tiles so that they are ordered as:
where the only legal operation is to exchange 'x' with one of the tiles with which it shares an edge. As an example, the following sequence of moves solves a slightly scrambled puzzle:
The letters in the previous row indicate which neighbor of the 'x' tile is swapped with the 'x' tile at each step; legal values are 'r','l','u' and 'd', for right, left, up, and down, respectively.
Not all puzzles can be solved; in 1870, a man named Sam Loyd was famous for distributing an unsolvable version of the puzzle, and
frustrating many people. In fact, all you have to do to make a regular puzzle into an unsolvable one is to swap two tiles (not counting the missing 'x' tile, of course).
In this problem, you will write a program for solving the less well-known 8-puzzle, composed of tiles on a three by three
arrangement.
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 x
where the only legal operation is to exchange 'x' with one of the tiles with which it shares an edge. As an example, the following sequence of moves solves a slightly scrambled puzzle:
1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4
5 6 7 8 5 6 7 8 5 6 7 8 5 6 7 8
9 x 10 12 9 10 x 12 9 10 11 12 9 10 11 12
13 14 11 15 13 14 11 15 13 14 x 15 13 14 15 x
r-> d-> r->
The letters in the previous row indicate which neighbor of the 'x' tile is swapped with the 'x' tile at each step; legal values are 'r','l','u' and 'd', for right, left, up, and down, respectively.
Not all puzzles can be solved; in 1870, a man named Sam Loyd was famous for distributing an unsolvable version of the puzzle, and
frustrating many people. In fact, all you have to do to make a regular puzzle into an unsolvable one is to swap two tiles (not counting the missing 'x' tile, of course).
In this problem, you will write a program for solving the less well-known 8-puzzle, composed of tiles on a three by three
arrangement.
Input
You will receive a description of a configuration of the 8 puzzle. The description is just a list of the tiles in their initial positions, with the rows listed from top to bottom, and the tiles listed from left to right within a row, where the tiles are represented by numbers 1 to 8, plus 'x'. For example, this puzzle
is described by this list:
1 2 3
x 4 6
7 5 8
is described by this list:
1 2 3 x 4 6 7 5 8
Output
You will print to standard output either the word ``unsolvable'', if the puzzle has no solution, or a string consisting entirely of the letters 'r', 'l', 'u' and 'd' that describes a series of moves that produce a solution. The string should include no spaces and start at the beginning of the line.
Sample Input
2 3 4 1 5 x 7 6 8
Sample Output
ullddrurdllurdruldr
Source
South Central USA 1998
八数码问题,目标状态固定,给数据用的是一维。
A*算法+二叉堆。估价函数写的是位移差的和。
#include
<
stdio.h
>
#include < string .h >
#include < math.h >
struct Eight {
int value;
int status[ 3 ][ 3 ];
char walked[ 60 ];
char str[ 15 ];
int xx,xy;
};
struct EightExtented {
bool left,right;
};
EightExtented eighte[ 370000 ];
Eight eight[ 370000 ];
bool hashtable[ 363000 ] = { false };
bool solved = false ;
int jc[ 10 ] = { 1 , 1 , 2 , 6 , 24 , 120 , 720 , 5040 , 40320 , 362880 };
int tail = 0 ;
char start[ 10 ];
int hmove[ 4 ][ 2 ] = {{ 0 , 1 },{ 0 , - 1 },{ - 1 , 0 },{ 1 , 0 }};
int cvalue();
void init()
{
int i;
char temp;
for (i = 0 ;i < 9 ;i ++ )
{
do
{
scanf( " %c " , & temp);
} while (temp == ' ' );
start[i] = temp;
if (start[i] != ' x ' ) eight[ 0 ].status[i / 3 ][i % 3 ] = start[i] - ' 0 ' ;
else {
eight[ 0 ].status[i / 3 ][i % 3 ] = 9 ;
eight[ 0 ].xx = i / 3 ;eight[ 0 ].xy = i % 3 ;
}
}
eight[ 0 ].value = cvalue();
tail ++ ;
}
int hash()
{
int rev[ 10 ] = { 0 };
int i,j;
int loc;
int hashvalue = 0 ;
for (i = 0 ;i < 9 ;i ++ )
{
if (eight[tail].str[i] == ' x ' ) {
loc = i;
continue ;
}
for (j = i + 1 ;j < 9 ;j ++ )
{
if ((eight[tail].str[j] != ' x ' ) && (eight[tail].str[i] > eight[tail].str[j])) rev[eight[tail].str[i] - ' 0 ' - 1 ] ++ ;
}
}
for (i = 0 ;i < 9 ;i ++ ) hashvalue += rev[i] * jc[i];
hashvalue += jc[ 8 ] * ( 9 - loc - 1 );
return hashvalue;
}
bool able()
{
int i,j;
int sum = 0 ;
for (i = 0 ;i < 8 ;i ++ )
for (j = i + 1 ;j < 9 ;j ++ )
if ((start[i] != ' x ' ) && (start[j] != ' x ' ) && (start[i] > start[j])) sum ++ ;
if (sum % 2 == 0 ) return true ;
else return false ;
}
int cvalue()
{
int i,j;
int value = 0 ;
for (i = 0 ;i < 3 ;i ++ )
for (j = 0 ;j < 3 ;j ++ )
value += fabs((eight[tail].status[i][j] - 1 ) / 3 - i) + fabs((eight[tail].status[i][j] - 1 ) % 3 - j);
return value;
}
// 0 right, 1 left, 2 up, 3 down
bool move( int way)
{
int x,y;
int i,j,l;
char temp;
if (strlen(eight[ 0 ].walked) >= 50 ) {
return false ;
}
x = eight[ 0 ].xx + hmove[way][ 0 ];
y = eight[ 0 ].xy + hmove[way][ 1 ];
if ( ! ((x >= 0 ) && (x < 3 ) && (y >= 0 ) && (y < 3 ))) return false ;
for (i = 0 ;i < 3 ;i ++ )
for (j = 0 ;j < 3 ;j ++ ) eight[tail].status[i][j] = eight[ 0 ].status[i][j];
eight[tail].status[eight[ 0 ].xx][eight[ 0 ].xy] = eight[tail].status[x][y];
eight[tail].status[x][y] = 9 ;
eight[tail].xx = x;eight[tail].xy = y;
for (i = 0 ;i < 3 ;i ++ )
for (j = 0 ;j < 3 ;j ++ ) if (eight[tail].status[i][j] != 9 ) eight[tail].str[i * 3 + j] = eight[tail].status[i][j] + ' 0 ' ;
else eight[tail].str[i * 3 + j] = ' x ' ;
eight[tail].str[ 9 ] = 0 ;
if (hashtable[hash()]) return false ;
else hashtable[hash()] = true ;
strcpy(eight[tail].walked,eight[ 0 ].walked);
switch (way)
{
case 0 : temp = ' r ' ; break ;
case 1 : temp = ' l ' ; break ;
case 2 : temp = ' u ' ; break ;
case 3 : temp = ' d ' ; break ;
}
l = strlen(eight[tail].walked);
eight[tail].walked[l] = temp;
eighte[tail].left =- 1 ;eighte[tail].right =- 1 ;
eight[tail].walked[l + 1 ] = 0 ;
eight[tail].value = cvalue() * 10 + l + 1 ;
eighte[tail].left = false ;eighte[tail].right = false ;
return true ;
}
void solve()
{
int i,t;
Eight temp;
while ( ! solved)
{
for (i = 0 ;i < 4 ;i ++ )
{
if (move(i)) {
if (tail > 1 ) {
t = tail;
while ((t > 1 ) && (eight[t].value < eight[t / 2 ].value))
{
temp = eight[t / 2 ];
eight[t / 2 ] = eight[t];
eight[t] = temp;
t /= 2 ;
}
}
if (tail % 2 == 0 ) eighte[tail / 2 ].left = true ;
else eighte[tail / 2 ].right = true ;
tail ++ ;
}
}
if (eight[ 0 ].value - strlen(eight[ 0 ].walked) == 0 ) {
printf( " %s\n " ,eight[ 0 ].walked);
solved = true ;
}
eight[ 0 ] = eight[ 1 ];
eight[ 1 ] = eight[tail - 1 ];
// printf("%s %s %d\n",eight[0].str,eight[0].walked,eight[0].value);
tail -- ;
if (tail % 2 == 0 ) eighte[tail / 2 ].left = false ;
else eighte[tail / 2 ].right = false ;
t = 1 ;
while (t * 2 < tail)
{
if (eight[t].value > eight[t * 2 ].value) {
if (eighte[t * 2 + 1 ].right && eight[t * 2 + 1 ].value < eight[t * 2 ].value) {
temp = eight[t];
eight[t] = eight[t * 2 + 1 ];
eight[t * 2 + 1 ] = temp;
t = t * 2 + 1 ;
}
else {
temp = eight[t];
eight[t] = eight[t * 2 ];
eight[t * 2 ] = temp;
t = t * 2 ;
}
}
else if (eighte[t * 2 + 1 ].right && eight[t].value > eight[t * 2 + 1 ].value) {
temp = eight[t];
eight[t] = eight[t * 2 + 1 ];
eight[t * 2 + 1 ] = temp;
t = t * 2 + 1 ;
}
else break ;
}
}
}
int main()
{
// freopen("test.out","w",stdout);
init();
if ( ! able()) {
printf( " unsolvable\n " );
return 0 ;
}
else solve();
return 0 ;
}
#include < string .h >
#include < math.h >
struct Eight {
int value;
int status[ 3 ][ 3 ];
char walked[ 60 ];
char str[ 15 ];
int xx,xy;
};
struct EightExtented {
bool left,right;
};
EightExtented eighte[ 370000 ];
Eight eight[ 370000 ];
bool hashtable[ 363000 ] = { false };
bool solved = false ;
int jc[ 10 ] = { 1 , 1 , 2 , 6 , 24 , 120 , 720 , 5040 , 40320 , 362880 };
int tail = 0 ;
char start[ 10 ];
int hmove[ 4 ][ 2 ] = {{ 0 , 1 },{ 0 , - 1 },{ - 1 , 0 },{ 1 , 0 }};
int cvalue();
void init()
{
int i;
char temp;
for (i = 0 ;i < 9 ;i ++ )
{
do
{
scanf( " %c " , & temp);
} while (temp == ' ' );
start[i] = temp;
if (start[i] != ' x ' ) eight[ 0 ].status[i / 3 ][i % 3 ] = start[i] - ' 0 ' ;
else {
eight[ 0 ].status[i / 3 ][i % 3 ] = 9 ;
eight[ 0 ].xx = i / 3 ;eight[ 0 ].xy = i % 3 ;
}
}
eight[ 0 ].value = cvalue();
tail ++ ;
}
int hash()
{
int rev[ 10 ] = { 0 };
int i,j;
int loc;
int hashvalue = 0 ;
for (i = 0 ;i < 9 ;i ++ )
{
if (eight[tail].str[i] == ' x ' ) {
loc = i;
continue ;
}
for (j = i + 1 ;j < 9 ;j ++ )
{
if ((eight[tail].str[j] != ' x ' ) && (eight[tail].str[i] > eight[tail].str[j])) rev[eight[tail].str[i] - ' 0 ' - 1 ] ++ ;
}
}
for (i = 0 ;i < 9 ;i ++ ) hashvalue += rev[i] * jc[i];
hashvalue += jc[ 8 ] * ( 9 - loc - 1 );
return hashvalue;
}
bool able()
{
int i,j;
int sum = 0 ;
for (i = 0 ;i < 8 ;i ++ )
for (j = i + 1 ;j < 9 ;j ++ )
if ((start[i] != ' x ' ) && (start[j] != ' x ' ) && (start[i] > start[j])) sum ++ ;
if (sum % 2 == 0 ) return true ;
else return false ;
}
int cvalue()
{
int i,j;
int value = 0 ;
for (i = 0 ;i < 3 ;i ++ )
for (j = 0 ;j < 3 ;j ++ )
value += fabs((eight[tail].status[i][j] - 1 ) / 3 - i) + fabs((eight[tail].status[i][j] - 1 ) % 3 - j);
return value;
}
// 0 right, 1 left, 2 up, 3 down
bool move( int way)
{
int x,y;
int i,j,l;
char temp;
if (strlen(eight[ 0 ].walked) >= 50 ) {
return false ;
}
x = eight[ 0 ].xx + hmove[way][ 0 ];
y = eight[ 0 ].xy + hmove[way][ 1 ];
if ( ! ((x >= 0 ) && (x < 3 ) && (y >= 0 ) && (y < 3 ))) return false ;
for (i = 0 ;i < 3 ;i ++ )
for (j = 0 ;j < 3 ;j ++ ) eight[tail].status[i][j] = eight[ 0 ].status[i][j];
eight[tail].status[eight[ 0 ].xx][eight[ 0 ].xy] = eight[tail].status[x][y];
eight[tail].status[x][y] = 9 ;
eight[tail].xx = x;eight[tail].xy = y;
for (i = 0 ;i < 3 ;i ++ )
for (j = 0 ;j < 3 ;j ++ ) if (eight[tail].status[i][j] != 9 ) eight[tail].str[i * 3 + j] = eight[tail].status[i][j] + ' 0 ' ;
else eight[tail].str[i * 3 + j] = ' x ' ;
eight[tail].str[ 9 ] = 0 ;
if (hashtable[hash()]) return false ;
else hashtable[hash()] = true ;
strcpy(eight[tail].walked,eight[ 0 ].walked);
switch (way)
{
case 0 : temp = ' r ' ; break ;
case 1 : temp = ' l ' ; break ;
case 2 : temp = ' u ' ; break ;
case 3 : temp = ' d ' ; break ;
}
l = strlen(eight[tail].walked);
eight[tail].walked[l] = temp;
eighte[tail].left =- 1 ;eighte[tail].right =- 1 ;
eight[tail].walked[l + 1 ] = 0 ;
eight[tail].value = cvalue() * 10 + l + 1 ;
eighte[tail].left = false ;eighte[tail].right = false ;
return true ;
}
void solve()
{
int i,t;
Eight temp;
while ( ! solved)
{
for (i = 0 ;i < 4 ;i ++ )
{
if (move(i)) {
if (tail > 1 ) {
t = tail;
while ((t > 1 ) && (eight[t].value < eight[t / 2 ].value))
{
temp = eight[t / 2 ];
eight[t / 2 ] = eight[t];
eight[t] = temp;
t /= 2 ;
}
}
if (tail % 2 == 0 ) eighte[tail / 2 ].left = true ;
else eighte[tail / 2 ].right = true ;
tail ++ ;
}
}
if (eight[ 0 ].value - strlen(eight[ 0 ].walked) == 0 ) {
printf( " %s\n " ,eight[ 0 ].walked);
solved = true ;
}
eight[ 0 ] = eight[ 1 ];
eight[ 1 ] = eight[tail - 1 ];
// printf("%s %s %d\n",eight[0].str,eight[0].walked,eight[0].value);
tail -- ;
if (tail % 2 == 0 ) eighte[tail / 2 ].left = false ;
else eighte[tail / 2 ].right = false ;
t = 1 ;
while (t * 2 < tail)
{
if (eight[t].value > eight[t * 2 ].value) {
if (eighte[t * 2 + 1 ].right && eight[t * 2 + 1 ].value < eight[t * 2 ].value) {
temp = eight[t];
eight[t] = eight[t * 2 + 1 ];
eight[t * 2 + 1 ] = temp;
t = t * 2 + 1 ;
}
else {
temp = eight[t];
eight[t] = eight[t * 2 ];
eight[t * 2 ] = temp;
t = t * 2 ;
}
}
else if (eighte[t * 2 + 1 ].right && eight[t].value > eight[t * 2 + 1 ].value) {
temp = eight[t];
eight[t] = eight[t * 2 + 1 ];
eight[t * 2 + 1 ] = temp;
t = t * 2 + 1 ;
}
else break ;
}
}
}
int main()
{
// freopen("test.out","w",stdout);
init();
if ( ! able()) {
printf( " unsolvable\n " );
return 0 ;
}
else solve();
return 0 ;
}