八数码难题

题目描述html

在3×3的棋盘上,摆有八个棋子,每一个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子能够移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。ios

输入输出格式markdown

输入格式:
输入初始状态,一行九个数字,空格用0表示布局

输出格式:
只有一行,该行只有一个数字,表示从初始状态到目标状态须要的最少移动次数(测试数据中无特殊没法到达目标状态数据)post

输入输出样例测试

输入样例#1: 复制
283104765
输出样例#1: 复制
4spa

本题正解应该是康托展开 + bfs 可是我弱啊,并不会康托展开,可是其实bfs + map判重也是能够过的,毕竟棋盘并非很大,只是3 * 3大小而已,(我感受IDA也能够,可是我并无打出来)。
这道题,我一开始是9位数字改为3
3 来存储,后来在用map判重的时候我发现还要转回来,因此我索性就直接在这个9位字符串上进行操做,对于上下左右进行转移,直接swap(),可是后面必定要再swap()回来,由于在开始调用一个新的队列队首时,此时用的都是当前从队列中取出来的那个九位字符串,若是不修改回来,循环下一次时,会发生转移的两点都不是0的状况,同时为了避免让程序重复搜索或者陷入一个循环,须要用map<string,int>来判重,此时当你写完进行Ctrl c ,Ctrl v以后你会发现你满心欢喜的等待的AC并不会出现,却而代之的是WA ,这是为何呢?
其实缘由就是,当你进行转移操做时,3,-3只需断定在棋盘内便可并不会出现什么问题,但(从第零位开始)是1对于第三位,第六位,-1对于第二位,第五位,都是不可能成立的,由于此时他们位于最边缘当这样移动后是不成立的,须要进行特判,而后就能够愉快地AC了。code

贴代码:htm

#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<map> #include<queue> using namespace std; string n; int ans = 200000; map<string,int>flag; int move[5] = {0,3,-3,-1,1};//四个方向 int start; string aim = "123804765"; int check(string a){//判断全局,是否到达目标状态 for(int i = 0; i<=8; i++){ if(a[i] != aim[i])return 0; } return 1; } queue<string>que; queue<int>q; int dx,begin; int main(){ cin >> n; que.push(n); q.push(0); while(!que.empty()){ string f = que.front();que.pop(); int v = q.front();q.pop(); if(flag[f] == 1)continue; if(check(f)){ ans = min(ans,v); continue; } flag[f] = 1; for(int i = 0; i<=8; i++){ if(f[i] == '0'){ dx = i; break; } } for(int i = 1; i<=4; i++){ //特判特殊点 if(dx == 3 && move[i] == -1)continue; if(dx == 6 && move[i] == -1)continue; if(dx == 2 && move[i] == 1)continue; if(dx == 5 && move[i] == 1)continue; //若是移动符合条件 if(dx + move[i] <= 8 && dx + move[i] >= 0){ swap(f[dx+move[i]],f[dx]); if(flag[f] == 1){//此状态已经搜过 swap(f[dx+move[i]],f[dx]);continue; } que.push(f); q.push(v+1); swap(f[dx+move[i]],f[dx]); } } } cout <<ans; return 0; } #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<map> #include<queue> using namespace std; string n; int ans = 200000; map<string,int>flag; int move[5] = {0,3,-3,-1,1};//四个方向 int start; string aim = "123804765"; int check(string a){//判断全局,是否到达目标状态 for(int i = 0; i<=8; i++){ if(a[i] != aim[i])return 0; } return 1; } queue<string>que; queue<int>q; int dx,begin; int main(){ cin >> n; que.push(n); q.push(0); while(!que.empty()){ string f = que.front();que.pop(); int v = q.front();q.pop(); if(flag[f] == 1)continue; if(check(f)){ ans = min(ans,v); continue; } flag[f] = 1; for(int i = 0; i<=8; i++){ if(f[i] == '0'){ dx = i; break; } } for(int i = 1; i<=4; i++){ //特判特殊点 if(dx == 3 && move[i] == -1)continue; if(dx == 6 && move[i] == -1)continue; if(dx == 2 && move[i] == 1)continue; if(dx == 5 && move[i] == 1)continue; //若是移动符合条件 if(dx + move[i] <= 8 && dx + move[i] >= 0){ swap(f[dx+move[i]],f[dx]); if(flag[f] == 1){//此状态已经搜过 swap(f[dx+move[i]],f[dx]);continue; } que.push(f); q.push(v+1); swap(f[dx+move[i]],f[dx]); } } } cout <<ans; return 0; }

转载于:https://www.cnblogs.com/Euplectella/p/9929049.htmlblog