最近做各种各样的BFS题目(八数码,翻硬币,倒水问题,数字格子问题),方法大致是一样的,于是我整理成了自创算法状态BFS。
下面举例用数字格子问题(这道题题号148,前面3个题号对应另外三题)
原理和BFS差不多,用node结构体存储一个状态,用string存储状态,比如把:
7 6 5 8
2 3 4 1
改成
"76582341"。
node还要存储steps表示第几步。
因为这些题都问的是步数(有的还有做不到的情况),所以我们定义BFS是int。这里我们用map<string,bool>(倒水直接用二维数组)来表示状态是否出现过,防止重复计算,导致超时。
然后我们可以分几个函数来表示状态的变化,最后在bfs里面检查,如果可以添加就添加。
代码(加了注释):
#include<iostream>
#include<map>
#include<queue>//头文件
using namespace std;
string st;//初始状态
const string end="12348765";//目标状态
map<string,bool> mp;//去重
struct node{
string str;
int steps;//状态和步数
}t,noww;//noww是现在状态,t是辅助存储
queue<node> q;//BFS必须用的
void shuru(){//专门用一个输入
char c;
for(int i=1;i<=8;i++){
cin>>c;
st+=c;
}
}
string l,a,b,c;//l省空间就避免重复定义,a,b,c是存储下面三个结果的
string sxjh(string now){//上下交换
l="";
for(int i=4;i<8;i++) l+=now[i];
for(int i=0;i<4;i++) l+=now[i];
return l;
}
string xypy(string now){//向右平移
l=now[3];
for(int i=0;i<3;i++) l+=now[i];
l+=now[7];
for(int i=4;i<7;i++) l+=now[i];
return l;
}
string zjxz(string now){//中间旋转
l=now[0];
l+=now[5];
l+=now[1];
l+=now[3];
l+=now[4];
l+=now[6];
l+=now[2];
l+=now[7];
return l;
}
int bfs(){//状态BFS
q.push(node{st,0});//初始状态
while(!q.empty()){
noww=q.front();
//cout<<"aba:"<<noww.str<<endl;
if(noww.str==end){//就是目标状态,直接结束
return noww.steps;
}
q.pop();
a=sxjh(noww.str);//分别存这三种结果
b=xypy(noww.str);
c=zjxz(noww.str);
//cout<<a<<","<<b<<","<<c<<endl;
if(!mp[a]){//没有出现过
mp[a]=1;//标记为出现过
t.str=a;
t.steps=noww.steps+1;//设定状态
q.push(t);//加入队列
}
if(!mp[b]){//同上
mp[b]=1;
t.str=b;
t.steps=noww.steps+1;
q.push(t);
}
if(!mp[c]){//同上
mp[c]=1;
t.str=c;
t.steps=noww.steps+1;
q.push(t);
}
}
return -1;//没有找到(虽然不可能,但是以防万一)就返回-1
}
int main(){
shuru();//输入
cout<<bfs()<<endl;//直接输出结果,如果可能做不到就要专门加一个判断是不是-1
return 0;
}