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;
}