1849: 【基础算法】8数码问题版本一
题目描述
在一个3*3的九宫格棋盘里,放有8个数码,数码的数字分别是1~8等8个数字。可以通过在九宫格里平移数码来改变状态。数码在任何情况下都不能离开棋盘。给出8个数码的初始状态(没放数码的空格用0表示)和目标状态,问从初始状态到目标状态,最少需要经过多少次移动操作。
例如,初始状态为:
2 6 4
1 3 7
0 5 8
目标状态是:
8 1 5
7 3 6
4 0 2
最少的移动步数为31步。
输入
第1行:9个空格分开的整数,表示初始状态
第2行:9个空格分开的整数,表示目标状态
整数都在0~8范围内,且不重复
输出
第1行:1个整数,表示从初始状态到目标状态的最少移动步数。如果无解,输出-1
样例输入
Copy (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)
2 6 4 1 3 7 0 5 8
8 1 5 7 3 6 4 0 2
样例输出
31
解一:单向BFS
好慢的吧
解二:双向BFS
模型:当知道开始状态和结束状态,需要求一条从s到t的一条最短路径
当单向搜索的时候,搜索的隐式树呈爆炸式增长,好恐怖的。。
不过如果双向搜,会避免掉很多,时间复杂度由K^L变为2*(K^(L/2)),将大大减少。(K为度数,L为层数)
比如说单向是一个大三角,双向就是大三角中的一个小“菱形”(还是比较像..)
实现的时候用一个队列即可,先把s和t压入queue,挨着广搜。由于是广搜,s和t的子状态都是“一块一块的”,不会混在一起。
代码比较丑:
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define MAXN 9
#define MAXKT 362880
struct node{
char s[MAXN+10];
int step;
bool flag;
int blank;
};
int pos,steps[MAXKT+10],w[MAXN+10];
int dir[4+5]={
1,-1,3,-3};
bool vis[2+5][MAXKT+10];
char s[MAXN+10],t[MAXN+10];
void read()
{
int a;
for(int i=0;i<9;i++){
scanf("%d",&a);
s[i]=a+'0';
}
for(int i=0;i<9;i++){
scanf("%d",&a);
t[i]=a+'0';
}
w[8]=0; w[7]=1;
for(int i=6;i>=0;i--) w[i]=w[i+1]*(8-i);
}
int kangtuo(char *x)
{
int ret=0;
for(int i=0;i<9;i++){
if(x[i]=='0'){
pos=i; continue;
}
for(int j=i+1;j<9;j++)
if(x[j]<x[i])
ret+=w[i];
}
return ret;
}
void double_BFS()
{
queue<node> que;
int num=kangtuo(s);
node start; memcpy(start.s,s,sizeof s);start.step=0,start.flag=0,start.blank=pos;
que.push(start);
vis[0][num]=true;
num=kangtuo(t);
node end; memcpy(end.s,t,sizeof s);end.step=0,end.flag=1,end.blank=pos;
que.push(end);
vis[1][num]=true;
while(!que.empty()){
node cur=que.front(); que.pop();
node next;
num=kangtuo(cur.s);
char state[MAXN+10];
memcpy(state,cur.s,sizeof cur.s);
for(int i=0;i<4;i++){
int newpos=cur.blank+dir[i];
if(newpos>=0&&newpos<9&&((newpos/3==cur.blank/3)||(newpos%3==cur.blank%3))){
//同一列||同一行
swap(state[cur.blank],state[newpos]);
int newnum=kangtuo(state);
if(vis[!cur.flag][newnum]){
printf("%d\n",cur.step+steps[newnum]+1);
return ;
}
else if(!vis[cur.flag][newnum]){
vis[cur.flag][newnum]=true;
steps[newnum]=cur.step+1;