codevs1225: 八数码难题
题目描述 Description
Yours和zero在研究A*启发式算法.拿到一道经典的A*问题,但是他们不会做,请你帮他们.
问题描述
在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。
输入描述 Input Description
输入初试状态,一行九个数字,空格用0表示
输出描述 Output Description
只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)
样例输入 Sample Input
283104765
样例输出 Sample Output
4
题解
写过poj和hdu的八数码以后写这道题处理起来就轻松多了。。裸题没啥说的,注意一下估价函数不计算0到目标位置的曼哈顿距离,否则是错误的(有兴趣的自己证明一下)。
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 int dx[5]={0,0,1,-1},dy[5]={1,-1,0,0}; 6 int lastx[10]={1,0,0,0,1,2,2,2,1},lasty[10]={1,0,1,2,2,2,1,0,0}; 7 int a[15],deep; 8 bool Ok(int x,int y) 9 { 10 if(x<0||x>2||y<0||y>2)return false; 11 return true; 12 } 13 bool Nofa(int x,int y) 14 { 15 if(x>y)swap(x,y); 16 if(x==0&&y==1)return false; 17 if(x==2&&y==3)return false; 18 return true; 19 } 20 void dfs(int step,int h,int dir,int now) 21 { 22 if(step+h>deep)return ; 23 if(!h) 24 { 25 printf("%d",deep); 26 exit(0); 27 } 28 int x=now/3;int y=now%3; 29 for(int i=0 ; i<4 ; ++i ) 30 { 31 int xx=x+dx[i];int yy=y+dy[i]; 32 if(Ok(xx,yy)&&Nofa(dir,i)) 33 { 34 int zz=xx*3+yy; 35 int ht=h-(abs(lastx[a[zz]]-xx)+abs(lasty[a[zz]]-yy))+(abs(lastx[a[zz]]-x)+abs(lasty[a[zz]]-y)); 36 swap(a[now],a[zz]); 37 dfs(step+1,ht,i,zz); 38 swap(a[now],a[zz]); 39 } 40 } 41 } 42 int Get() 43 { 44 int ret(0); 45 for(int i=0 ; i<9 ; ++i) 46 { 47 if(a[i]==0)continue; 48 int x=i/3;int y=i%3; 49 ret+=abs(lastx[a[i]]-x)+abs(lasty[a[i]]-y); 50 } 51 return ret; 52 } 53 int main() 54 { 55 char str[15]; 56 int pos; 57 scanf("%s",str); 58 for(int i=0 ; i<9 ; ++i) 59 { 60 a[i]=str[i]-'0'; 61 if(!a[i])pos=i; 62 } 63 int h=Get(); 64 for( deep=0 ; ; deep++ ) 65 dfs(0,h,4,pos); 66 return 0; 67 }