八数码问题也称为九宫问题。在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同。棋盘上还有一个空格,与空格相邻的棋子可以移到空格中。要求解决的问题是:给出一个初始状态和一个目标状态,找出一种从初始转变成目标状态的移动棋子步数最少的移动步骤。(用0表示空格)
思路:把八数码问题归结为图上的最短路问题。开始状态对应起点,目标状态对应终点。用广搜去搜索就可以了。
用STL的map来判重。也可以用set来判重。我看其他大神的博客说用hash表来判重会更快,还有用双向搜索来做的,有兴趣的可以自己写写。
http://www.cnblogs.com/FreeDestiny/archive/2011/10/27/2226709.html
<pre name="code" class="cpp">#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <map>
#include <stack>
#include <queue>
#include <list>
#include <set>
#define LL long long
#define INF 0x7fffffff
#define FIN 0x80000000
using namespace std;
typedef int State[9];
State st[500000],gold;
int dist[500000];
map<int,int> mp;
int dx[]={0,1,0,-1},dy[]={1,0,-1,0};
bool ispan(int k)
{
int res=0;
for(int i=0;i<9;i++) res=res*10+st[k][i];
if(mp[res]) return false;
mp[res]=1;
return true;
}
int bfs()
{
queue<int> que;
que.push(1);
ispan(1);
int u=2;
while(que.size())
{
int v=que.front(); que.pop();
State &s=st[v];
// for(int i=0;i<9;i++) printf("%d ",s[i]); printf("\n");
if(memcmp(s,gold,sizeof(State))==0) return v;
int x,y,z;
for(z=0;z<9;z++) if(s[z]==0) break;
x=z/3; y=z%3;
for(int i=0;i<4;i++)
{
int nx=x+dx[i];
int ny=y+dy[i];
int nz=nx*3+ny;
if(nx>=0&&nx<3&&ny>=0&&ny<3)
{
State &t=st[u];
memcpy(&t,&s,sizeof(State));
t[nz]=s[z];
t[z]=s[nz];
dist[u]=dist[v]+1;
if(ispan(u))
{
que.push(u);
u++;
}
}
}
}
return -1;
}
int main()
{
for(int i=0;i<9;i++) scanf("%d",&st[1][i]);
for(int i=0;i<9;i++) scanf("%d",&gold[i]);
int ans=bfs();
printf("%d",ans==-1?ans:dist[ans]);
}
/*
1 2 3 4 5 6 7 8 0
8 7 6 5 4 3 2 1 0
2 6 4 1 3 7 0 5 8
8 1 5 7 3 6 4 0 2
正确输出对应是 30、 31
*/