题目描述
在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。
输入输出格式
输入格式:
输入初始状态,一行九个数字,空格用0表示
输出格式:
只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)
输出样例
4
这是 alphar 学长带我入门广搜的例题,当时完全是抄代码,因为完全没有代码功力
当时把 codevs 的题目A掉了,现在偶然见到 luogu 有人求助这道题目,点开一看,又是不一样的方法
思路:
这道题目关键在于判重,因为如果只是一个简单的搜索,它只会是瞎跑,杂乱无章,我们要做的就是规定它向着什么方向跑,以及不让他走了半天又绕回原地
于是就有了A*算法的思路
构造一个估价函数,其实说白了就是看他离终点还差多远
通过迭代加深的方法,如果当前状态可以到达终点,我们就继续往下走
至于估价函数……意会就好,无需证明
code
#include<stdio.h> #include<algorithm> using namespace std; bool flag; int k,sx,sy,mp[5][5]; int plan[5][5]={{1,2,3},{8,0,4},{7,6,5}}; int dx[]={1,0,0,-1}; int dy[]={0,1,-1,0}; bool check() { for(int i=0;i<3;i++) for(int j=0;j<3;j++) if(plan[i][j]!=mp[i][j]) return false; return true; } bool test(int stp) { int cnt=0; for(int i=0;i<3;++i) for(int j=0;j<3;++j) if(mp[i][j]!=plan[i][j]) if(++cnt+stp>k) return false; return true; } void star(int x,int y,int stp,int last) { if(stp==k) { if(check()) flag=1; return; } if(flag) return; for(int i=0;i<4;++i) { int nx=x+dx[i],ny=y+dy[i]; if(nx<0 || ny<0 || nx>2 || ny>2 || last+i==3) continue; swap(mp[x][y],mp[nx][ny]); if(test(stp)) star(nx,ny,stp+1,i); swap(mp[x][y],mp[nx][ny]); } } int main() { for(int i=0;i<=2;i++) for(int j=0;j<=2;j++) { char c; scanf("%c",&c); mp[i][j]=c-'0'; if(mp[i][j]==0) sx=i,sy=j; } if(check()) { printf("0");return 0; } while(++k) { star(sx,sy,0,-1); if(flag) { printf("%d",k); break; } } return 0; }