Eight
Description
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
1 2 3
x 4 6
7 5 8
is described by this list:
1 2 3 x 4 6 7 5 8
Output
Sample Input
2 3 4 1 5 x 7 6 8
Sample Output
ullddrurdllurdruldr
题意:给定一个二维图由其实状态得到目标状态输出最少步数的路径
题解:由起点开始搜索,单项BFS+hash。记录路径即可
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
int fan[9]={1,1,2,6,24,120,720,5040,40320};
int target[9]={1,2,3,4,5,6,7,8,0};
int sval,eval,po;
int visit[362881];
int c[9];
int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
int mg[1000];
struct lmx{
int a[9];
int step;
int pos;
int pre;
int dir;
};
void print(int i)
{
if(i==0) printf("u");
else if(i==1) printf("d");
else if(i==2) printf("l");
else if(i==3) printf("r");
}
int kgto(int c[],int n)
{
int i,j,num,s=0;
for(i=0;i<n-1;i++)
{
num=0;
for(j=i+1;j<n;j++)
{
if(c[j]<c[i]) num++;
}
s+=num*fan[8-i];
}
return s;
}
lmx s,t,h,ss;
lmx lm[362881];
int bfs()
{
visit[sval]=0;
int head=-1,rear=0,i,xx,yy,val,x,y;
memcpy(s.a,c,sizeof(c));
s.step=0;
s.pre=-1;
s.dir=-1;
s.pos=po;
lm[head+1]=s;
while(head<rear)
{
head++;
h=lm[head];
x=h.pos/3;
y=h.pos%3;
for(i=0;i<4;i++)
{
t=h;
xx=x+dir[i][0];
yy=y+dir[i][1];
if(xx>=0&&xx<3&&yy>=0&&yy<3)
{
swap(t.a[h.pos],t.a[xx*3+yy]);
t.pre=head;
t.dir=i;
val=kgto(t.a,9);
t.pos=3*xx+yy;
t.step=h.step+1;
if(visit[val]==-1)
{
if(val==eval) { ss=t;return t.step;}
lm[++rear]=t;
visit[val]=0;
}
}
}
}
return -1;
}
int main()
{
char mm[100],i,top;
for(i=0;i<9;i++)
{
cin>>mm[i];
if(mm[i]>='0'&&mm[i]<='8') c[i]=mm[i]-'0';
if(mm[i]=='x'){c[i]=0;po=i;}
}
eval=kgto(target,9);
sval=kgto(c,9);
memset(visit,-1,sizeof(visit));
top=0;
if(sval!=eval)
{
int temp=bfs();
if(temp==-1) puts("unsolvable");
else
{
while(ss.pre!=-1)
{
mg[top++]=ss.dir;
ss=lm[ss.pre];
}
for(i=top-1;i>=0;i--)
{
print(mg[i]);
}
puts("");
}
}
return 0;
}
解法2:
思路:由目标结点出发逆向打表记录路径
#include<stdio.h>
#include<iostream>
#include<string>
#include<algorithm>
#include<queue>
#include<string.h>
using namespace std;
const int MAX=1000000;
int sr[9],po;
int fan[9]={1,1,2,6,24,120,720,5040,40320};
bool visit[MAX];
string ss[MAX];
struct lmx{
int a[9];
int pos;
string str;
};
lmx s,t,h;
int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
char st[5]="durl";
int kgto(int m[],int n)
{
int i,j,num,s=0;
for(i=0;i<n-1;i++)
{
num=0;
for(j=i+1;j<n;j++)
{
if(m[j]<m[i]) num++;
}
s+=num*fan[8-i];
}
return s;
}
int bfs()
{
memset(visit,false,sizeof(visit));
int i,val,x,y,xx,yy;
queue<lmx>q;
for(i=0;i<8;i++)
{
s.a[i]=i+1;
}
s.a[8]=0;
s.pos=8;
s.str="";
q.push(s);
val=kgto(s.a,9);
visit[val]=true;
ss[val]="";
while(!q.empty())
{
h=q.front();
q.pop();
x=h.pos/3;
y=h.pos%3;
for(i=0;i<4;i++)
{
xx=x+dir[i][0];
yy=y+dir[i][1];
if(xx>=0&&xx<3&&yy>=0&&yy<3)
{
t=h;
swap(t.a[h.pos],t.a[xx*3+yy]);
t.pos=3*xx+yy;
val=kgto(t.a,9);
if(visit[val]==false)
{
visit[val]=true;
t.str=st[i]+t.str;
q.push(t);
ss[val]=t.str;
}
}
}
}
}
int main()
{
char ch;
int i;
bfs();
while(cin>>ch)
{
if(ch>='0'&&ch<='9') sr[0]=ch-'0';
if(ch=='x') {sr[0]=0;po=0;}
for(i=1;i<9;i++)
{
cin>>ch;
if(ch>='0'&&ch<='9') sr[i]=ch-'0';
else {sr[i]=0;po=i;}
}
int temp=kgto(sr,9);
if(visit[temp]==false) puts("unsolvable");
else cout<<ss[temp]<<endl;
}
return 0;
}