一、题意:类似于华容道,输入是8个数字,输入虽然是一行,但实际是以两行的方式操作的。0表示空位,别的相邻数字可移动到该位置上。求最少移动步骤得到指定的状态。
二、思路:这题可以用BFS来解决。因为在每一步可以产生两个状态,类似于走迷宫里的移动,不同的是这里的坐标变化是一维的:+1,-1,+4,-4。这里需要注意一点是坐标3不能+1,坐标4不能-1,因为这里是排两行的,所以这个小细节很关键。每个状态可以用字符串和0的坐标0来存储(map),并且可以用改字符串对应的整数来标记该状态是否出现过已达到剪枝的效果。这里用到了几个小技巧:1、int类型和string类型的相互转换 2、map的使用。用map来记录到各个状态的步数。如果用数组来存,会MLE。 3.打表。这个很关键,因为逆向思维来说,初始状态都是“01234567”,所以打表后后面直接查表,效率会高很多,不然会TLE。 4.pair函数的使用。用一个pair类型的队列来记录每一个状态以及这个状态下0的位置。 5.在做坐标交换时,我自定义了一个Change函数,也可以用系统自带的swap函数,更简洁。
三、代码:
#include"iostream" #include"stdio.h" #include"queue" #include"string.h" #include"map" #include"sstream" #include"stdlib.h" using namespace std; typedef pair<string,int> P; int inputSample[10]; string inputString; map<string,int>state; string Int2String(int &a) { ostringstream oss; oss<<a; return oss.str(); } bool Judge(int x) { if(x>=0&&x<8) return true; return false; } string Change(int a,int b,string str) { char tmp=str[a]; str[a]=str[b]; str[b]=tmp; return str; } int Bfs() { queue<P> que; que.push(P("01234567",0)); while(que.size()) { P p=que.front();que.pop(); int dir[4]={1,-1,4,-4}; for(int i=0;i<4;i++) { if(p.second==3&&dir[i]==1) continue; if(p.second==4&&dir[i]==-1) continue; int nx=p.second+dir[i]; if(Judge(nx)) { string str=Change(p.second,nx,p.first); if(state.find(str)==state.end()) { state[str]=state[p.first]+1; que.push(P(str,nx)); } } } } return -1; } int main() { // freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); state["01234567"]=0; Bfs(); while(scanf("%d",&inputSample[0])==1) { for(int i=1;i<8;i++) cin>>inputSample[i]; inputString=""; for(int i=0;i<8;i++) { inputString+=Int2String(inputSample[i]); } cout<<state[inputString]<<endl; } return 0; }