状态BFS

最近做各种各样的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;
}
posted @ 2021-07-30 17:24  cyx001  阅读(53)  评论(0编辑  收藏  举报