1225 八数码难题
题目描述Description
Yours和zero在研究A*启发式算法.拿到一道经典的A*问题,但是他们不会做,请你帮他们.
问题描述
在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。
输入描述Input Description
输入初试状态,一行九个数字,空格用0表示
输出描述Output Description
只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)
样例输入Sample Input
283104765
样例输出Sample Output
4
这题超经典,值得学搜索的人都去弄一下,可以先用广搜→双广→A*这样你的搜索就能掌握到方向了。
/*
八数码难题
单向bfs+康托展开+hash
*/
#include<iostream>
#include<cstring>
#include<cstdlib>
using namespace std;
const int dx[5]={0,0,0,1,-1};
const int dy[5]={0,1,-1,0,0};
struct Node
{
int mp[4][4];
int step;
};
Node e;
Node d[400005];
int hash[400005];
long fc[10]={1,1,2,6,24,120,720,5040,40320,362880};
long total=0;
long head=0, tail=0;
bool flag=false;
void debug(Node x)
{
for (int i=1; i<=3; i++)
{
for (int j=1; j<=3; j++)
cout<<x.mp[i][j]<<" ";
cout<<endl;
}
cout<<"##############"<<endl;
}
long KT(Node x)
{
int m[10];
int tot=0;
for (int i=1; i<=3; i++)
for (int j=1; j<=3; j++)
{
m[++tot]=x.mp[i][j];
//debug(x);
}
long num=1;
for (int i=1; i<=9; i++)
{
int temp=0;
for (int j=i+1; j<=9; j++)
{
if (m[i]>m[j])
{
temp++;
}
}
num+=fc[9-i]*temp;
}
return num;
}
bool Hash(Node x)
{
long y=KT(x);
if(!hash[y]){
hash[y]=1;
return true;
}
return false;
}
void sp(int &a, int &b)
{
int t=a;
a=b;
b=t;
}
bool pd(int x, int y)
{
if (x<0 || x>3 ||y<0 ||y>3) return 0;
else return 1;
}
void move(int x, int y)
{
for (int i=1; i<=4; i++)
{
int xx=dx[i]+x;
int yy=dy[i]+y;
if (pd(xx, yy))
{
tail++;
for (int i=1; i<=3; i++)
for (int j=1; j<=3; j++)
d[tail].mp[i][j]=d[head].mp[i][j];
sp(d[tail].mp[x][y], d[tail].mp[xx][yy]);
if (Hash(d[tail])) {
d[tail].step=d[head].step+1;
// debug(d[tail]);
if (hash[total])
{
flag=true;
return ;
}
}
else tail--;
}
}
}
void bfs()
{
while (head<=tail)
{
for (int i=1; i<=3; i++)
for (int j=1; j<=3; j++)
{
if (!d[head].mp[i][j])
{
move(i, j);
if (flag)
{
cout<<d[tail].step<<endl;
return;
}
break;
}
}
head++;
}
}
void init()
{
d[0].mp[1][1]=1; d[0].mp[1][2]=2; d[0].mp[1][3]=3;
d[0].mp[2][1]=8; d[0].mp[2][2]=0; d[0].mp[2][3]=4;
d[0].mp[3][1]=7; d[0].mp[3][2]=6; d[0].mp[3][3]=5;
d[0].step=0;
}
int main()
{
memset(hash, 0, sizeof(hash));
init();
for (int i=1; i<=3; i++)
for (int j=1; j<=3; j++)
{
char s;
cin>>s;
e.mp[i][j]=s-'0';
}
total=KT(e);
Hash(d[0]);
bfs();
return 0;
}
/*
八数码难题 双向bfs+hash+cantor 参考了hzwer大犇的代码,写的真不错
*/
#include<iostream>
#include<cstdlib>
#include<cstring>
using namespace std;
const int dx[5]={0,0,0,1,-1};
const int dy[5]={0,1,-1,0,0};
struct Node{
int mp[4][4];
};
Node d[2][400000];//0代表正向bfs, 1代表反向bfs ;
long fc[10]={1,1,2,6,24,120,720,5040,40320,362880};
int hash[2][400000];//hash判重+存储step
int step[2][400000]={0,0};
long head[2], tail[2]={1,1};
bool flag=0;
void debug1(int k, int temp)
{
cout<<temp<<"--------temp"<<endl;
cout<<k<<"---------bfs方向"<<endl;
cout<<hash[k][temp]<<endl;
cout<<"hash----------------"<<endl;
}
void debug(int b[4][4])
{
for (int i=1; i<=3; i++)
{
for (int j=1; j<=3; j++)
cout<<b[i][j]<<" ";
cout<<endl;
}
cout<<"#####################"<<endl;
}
long KT(int b[4][4])
{
int m[10];
int tot=0;
for (int i=1; i<=3; i++)
for (int j=1; j<=3; j++)
{
m[++tot]=b[i][j];
}
long num=1;
for (int i=1; i<=9; i++)
{
int temp=0;
for (int j=i+1; j<=9; j++)
if (m[i]>m[j]) temp++;
num+=fc[9-i]*temp;
}
return num;
}
void sp(int &a, int &b)
{
int t=a;
a=b;
b=t;
}
bool pd(int x, int y)
{
if (x<0 || x>3 || y<0 || y>3) return 0;
else return 1;
}
void bfs(int k)
{
int x=0, y=0;
for (int i=1; i<=3; i++)
for (int j=1; j<=3; j++)
{
if (d[k][head[k]].mp[i][j]==0)
{
x=i;
y=j;
break;
}
}
for (int i=1; i<=4; i++)
{
int xx=dx[i]+x;
int yy=dy[i]+y;
if (pd(xx, yy))
{
for (int i=1; i<=3; i++)
for (int j=1; j<=3; j++)
d[k][tail[k]].mp[i][j]=d[k][head[k]].mp[i][j];
sp(d[k][tail[k]].mp[x][y], d[k][tail[k]].mp[xx][yy]);
int temp=KT(d[k][tail[k]].mp);
if (hash[k][temp]==-1)
{
step[k][tail[k]]=step[k][head[k]]+1;
hash[k][temp]=step[k][tail[k]];
if(hash[0][temp]!=-1 && hash[1][temp]!=-1)
{
//cout<<d[k][tail[k]].step<<" "<<d[1-k][tail[k]-20].step<<endl;
cout<<hash[0][temp]+hash[1][temp]<<endl;
flag=1;
return ;
}
}
// cout<<tail[k]<<endl;
//debug(d[k][tail[k]].mp);
tail[k]++;
}
}
head[k]++;
}
void search()
{
while (!flag)
{
if (tail[0]-head[0]<=tail[1]-head[1]) bfs(0);
else bfs(1);
}
}
void init(int b[10])
{
d[0][0].mp[1][1]=1; d[0][0].mp[1][2]=2; d[0][0].mp[1][3]=3;
d[0][0].mp[2][1]=8; d[0][0].mp[2][2]=0; d[0][0].mp[2][3]=4;
d[0][0].mp[3][1]=7; d[0][0].mp[3][2]=6; d[0][0].mp[3][3]=5;
int tot=0;
for (int i=1; i<=3; i++) for (int j=1; j<=3; j++) d[1][0].mp[i][j]=b[++tot];
// debug(d[0][0].mp);
hash[0][KT(d[0][0].mp)]=hash[1][KT(d[1][0].mp)]=0;
// debug1(1, KT(d[1][0].mp));
}
int main()
{
memset(hash, -1, sizeof(hash));
int b[10];
string a;
cin>>a;
for (int i=0; i<a.size(); i++)
{
b[i+1]=a[i]-'0';
}
init(b);
search();
return 0;
}