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:
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, several descriptions of configuration of the 8 puzzle. One 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
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. Do not print a blank line between cases.
Sample Input
2 3 4 1 5 x 7 6 8
Sample Output
ullddrurdllurdruldr
因为最多只有9!种状态,一开始我想到的是直接暴力搜索起始状态到123456789x的状态,写完之后发现超时。
这里粘一下代码:
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn=362885;
char a[10];
int pos[4]={-3,3,-1,1};
char mea[6]="udlr";
char ans[maxn];
struct node
{
int id;
char a[10];
int pre;
int px;
char op;
}b[maxn];
int cnt;
int cnt2;
setSet;
ll change (char s[])
{
ll t=0;
for (int i=0;i<9;i++)
{
t=t*10+(s[i]-'0');
}
return t;
}
int judge (ll t)
{
if(Set.count(t)) return 0;
Set.insert(t);
return 1;
}
int bfs (int x)
{
queueq;
strcpy(b[0].a,a);
b[0].pre=-1;
b[0].px=x;
b[0].op=-1;
b[0].id=0;
q.push(b[0]);
cnt++;
ll t=change(b[0].a);
judge(t);
node now,next;
while(!q.empty())
{
now=q.front(); q.pop();
ll t=change(now.a);
if(t==123456780)
{
//printf("----\n");
node x=now;
while(x.pre!=-1)
{
ans[cnt2++]=x.op;
x=b[x.pre];
}
return 1;
}
for (int i=0;i<4;i++)
{
next=now;
int ch=now.px+pos[i];
if((i==2&&now.px%3==0)||(i==3&&now.px%3==2)) continue;
if(ch>=0&&ch<9)
{
swap(next.a[next.px],next.a[ch]);
next.px=ch;
ll t=change(next.a);
if(judge(t))
{
next.id=cnt;
next.pre=now.id;
next.op=i;
b[cnt++]=next;
q.push(next);
}
}
}
}
return -1;
}
int main()
{
while(scanf("%c ",&a[0])!=EOF)
{
int x;
for (int i=1;i<8;i++) scanf("%c ",&a[i]);
scanf("%c",&a[8]);
for (int i=0;i<9;i++)
{
if(a[i]=='x')
{
a[i]='0';
x=i;
}
}
getchar();
cnt=0; cnt2=0;
Set.clear();
if(bfs(x)!=-1)
{
for (int i=cnt2-1;i>=0;i--)
{
printf("%c",mea[ans[i]]);
}
printf("\n");
}
else
{
printf("unsolvable\n");
}
}
}
之后上网上搜了一下,发现应该从12345678x进行搜索,相当于进行打表,之后看看输入给出的状态是否可以从123456789x走到,这里需要储存走过的状态,网上普遍用了康托扩展,康托扩展确实使寻找状态快了很多,但是这个题目用set的话应该也能过,我感觉这个题目的侧重点应该是在打表上,康托扩展只是起到了锦上添花的效果。
这里贴一下AC代码,用了康托扩展。
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn=362885;
int pos[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
//储存前驱节点
int can[maxn];
//储存方向
char op[maxn];
char a[50];
int f[10];
struct node
{
int can; //现在节点的康托展开数
int a[10];
int x; //坐标
};
int cantor(int a[])
{
int t=0;
for (int i=0;i<9;i++)
{
int m=0;
for (int j=i+1;j<9;j++)
{
if(a[i]>a[j]) m++;
}
t+=m*f[8-i];
}
return t;
}
void bfs ()
{
queueq;
node now,next;
for (int i=0;i<9;i++) now.a[i]=i+1;
now.x=8;
now.can=0;
can[0]=0;
q.push(now);
while(!q.empty())
{
now=q.front(); q.pop();
for (int i=0;i<4;i++)
{
next=now;
int tx=now.x/3+pos[i][0];
int ty=now.x%3+pos[i][1];
if(tx>=0&&tx<3&&ty>=0&&ty<3)
{
next.x=tx*3+ty;
swap(next.a[tx*3+ty],next.a[now.x]);
next.can=cantor(next.a);
if(can[next.can]==-1)
{
can[next.can]=now.can;
if(i==0) op[next.can]='l';
else if(i==1) op[next.can]='r';
else if(i==2) op[next.can]='u';
else if(i==3) op[next.can]='d';
q.push(next);
}
}
}
}
}
int main()
{
f[0]=1;
for (int i=1;i<=9;i++) f[i]=i*f[i-1];
memset (can,-1,sizeof(can));
bfs();
while(gets(a)!=NULL)
{
int x,cnt=0;
int len=strlen(a);
int ca[10];
for (int i=0;i'0'&&a[i]<'9') ca[cnt++]=a[i]-'0';
}
int t=cantor(ca);
if(can[t]==-1) printf("unsolvable\n");
else
{
while(t)
{
printf("%c",op[t]);
t=can[t];
}
printf("\n");
}
}
}