bfs题总结(1)

【题目】迷宫题的改版,但要求找出到达终点的最少步数。

【题目分析】我们从起点出发,每次往下走最多有四种选择,对应搜索树的一层。使用dfs进行逐层搜索,这样当第一次在某层找到终点时就不必往下继续搜了。dfs要借助队列来实现,在这之前先练习下基本的树的广度优先搜索。

//对上面的树进行bfs搜索,结果为1 2 3 4 5 6 7 8
#include<iostream>
#include<queue>
using namespace std;
struct node{
	int data;
	node *left;
	node *right;
	node(int _data,node* _left=NULL,node * _right=NULL):data(_data),left(_left),right(_right){}; 
};
void bfs(node s){
	queue<node>q;
	q.push(s);
//当最后一层node都没有孩子的时候,队列没有补充了
	while(!q.empty()){
		node a=q.front();
		cout<<a.data<<endl;
		
		if(a.left!=NULL){
			q.push(*(a.left));
		}
		if(a.right!=NULL){
			q.push(*(a.right));
		}
		q.pop();
	}
}
int main (){
	node n4=node(4);
	node n5=node(5);
	node n6=node(6);
	node n7=node(7);
	node n2=node(2,&n4,&n5);
	node n3=node(3,&n6,&n7);
	node n1=node(1,&n2,&n3);
	bfs(n1);
	return 0;
} 
#include<iostream>
#include<queue>
using namespace std;
char mp[50][50];
bool vis[50][50];
int n,m,sx,sy,ans;
struct node{
	int x;
	int y;
	int step;
	node(int _x,int _y,int _step):x(_x),y(_y),step(_step){} 
};
int dir[4][2]={{-1,0},{0,1},{1,0},{0,-1}};
void bfs(){
	queue <node>q;
	q.push(node(sx,sy,0));
	vis[sx][sy]=true;
	int tx,ty;
	while(!q.empty()){
		node a=q.front();
		if(mp[a.x][a.y]=='t'){
			cout<<a.step<<endl;
			return ;
		} 
		
		q.pop();
		for(int i=0;i<4;i++){
			tx=a.x+dir[i][0];
			ty=a.y+dir[i][1];
			if(tx>=0&&ty>=0&&tx<n&&ty<m&&!vis[tx][ty]&&mp[tx][ty]!='#'){
				vis[tx][ty]=true;
				q.push(node(tx,ty,a.step+1));
			}
		}
	} 
	
	
}
int main (){
	cin>>n>>m;
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			cin>>mp[i][j];
			if(mp[i][j]=='s'){     //终点't'
				sx=i;
				sy=j;
			}
		}
	}
	bfs();
	return 0;
} 

 【代码总结】代码框架和bfs的二叉搜索树一致,先把初始节点push进去,然后访问节点即判断节点是否为迷宫终点,然后将该节点的子节点放到队尾,在放的时候要对节点也就是迷宫的坐标进行合法性判断,不能越界不能被访问过,不能是墙,然后标记为被访问过,放入队尾。一些非bfs基础代码结构的位置不固定,比如判断是否为终点,可以将该判断语句放在for循环之中。

【题目】一块牧草地,被分为若干块,如图是一个宽度 X=4,高度Y=3的草地,*表示有石头,若某处(Mx,My)有乳草,那么每周某块乳草将会向四周八个方向侵占,要求出过多长时间能侵占完所有草坪。

输入包括X,Y,Mx,My

【分析】和走迷宫类似,但搜索肯定是在最后一层的最右边那个结束的,所以要把全部节点搜完

#include<iostream>
#include<queue>
using namespace std;
char mp[50][50];
bool vis[50][50];
struct node{
	int x;
	int y;
	int week;
	node(int _x,int _y,int _week):x(_x),y(_y),week(_week){} 
};
int dir[8][2]={{-1,0},{-1,1},{0,1},{1,1},{1,0},{0,-1},{1,-1},{-1,-1}};
int X,Y,Mx,My,sx,sy,ans;
int bfs(){
	int tx,ty;
	queue <node>q;
	q.push(node(sx,sy,0));
	vis[sx][sy]=true;
	while(!q.empty()){
		node a=q.front();
		q.pop();
		//cout<<a.week<<endl;
		for(int i=0;i<8;i++){
			tx=a.x+dir[i][0];
			ty=a.y+dir[i][1];
			if(tx>=0&&ty>=0&&tx<Y&&ty<X&&!vis[tx][ty]&&mp[tx][ty]=='.'){
				vis[tx][ty]=true;
				ans=a.week+1;
				q.push(node(tx,ty,a.week+1));
			}
		}
	}

	return ans;
	
}
int main (){
	cin>>X>>Y>>Mx>>My;
	//数组坐标系下的sy就是Mx-1;
	sy=Mx-1;
	//sx就是My 
	sx=Y-1-sy;
	for(int i=0;i<Y;i++){
		for(int j=0;j<X;j++){
			cin>>mp[i][j];
		}
	}


	cout<<bfs()<<endl;
	return 0;
} 

【模拟赛类似题】

问题描述

  小明有一块空地,他将这块空地划分为 n 行 m 列的小块,每行和每列的长度都为 1。
  小明选了其中的一些小块空地,种上了草,其他小块仍然保持是空地。
  这些草长得很快,每个月,草都会向外长出一些,如果一个小块种了草,则它将向自己的上、下、左、右四小块空地扩展,这四小块空地都将变为有草的小块。
  请告诉小明,k 个月后空地上哪些地方有草。

输入格式

  输入的第一行包含两个整数 n, m。
  接下来 n 行,每行包含 m 个字母,表示初始的空地状态,字母之间没有空格。如果为小数点,表示为空地,如果字母为 g,表示种了草。
  接下来包含一个整数 k。

输出格式

  输出 n 行,每行包含 m 个字母,表示 k 个月后空地的状态。如果为小数点,表示为空地,如果字母为 g,表示长了草。

样例输入

4 5
.g...
.....
..g..
.....
2

样例输出

gggg.
gggg.
ggggg
.ggg.

评测用例规模与约定

  对于 30% 的评测用例,2 <= n, m <= 20。
  对于 70% 的评测用例,2 <= n, m <= 100。
  对于所有评测用例,2 <= n, m <= 1000,1 <= k <= 1000

#include<iostream>
#include<queue>
using namespace std;
char mp[50][50];
bool vis[50][50];

struct node{
	int x;
	int y;
	int week;
	node(int _x,int _y,int _week):x(_x),y(_y),week(_week){} 
};
int dir[4][2]={{-1,0},{0,1},{1,0},{0,-1}};
int n,m,k;
queue <node>q;

void bfs(){
	int tx,ty;
	while(!q.empty()){
		node a=q.front();
		q.pop();
		if(a.week==k){
			return;
		}
		for(int i=0;i<4;i++){
		
			tx=a.x+dir[i][0];
			ty=a.y+dir[i][1];
			if(tx>=0&&ty>=0&&tx<n&&ty<m&&mp[tx][ty]!='g'){
				
				mp[tx][ty]='g';
				q.push(node(tx,ty,a.week+1));
			}
		}
	}


	
}
int main (){
	cin>>n>>m;
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			cin>>mp[i][j];
			if(mp[i][j]=='g'){
				q.push(node(i,j,0));
			}
		}
	}
	cin>>k;
	bfs();
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			cout<<mp[i][j];	
		}
		cout<<endl;
	}

	return 0;
} 

【题目】平面魔方 

#include<iostream>
#include<queue>
#include<map>
using namespace std;
struct node{
	int a[3][3];

	
	 bool operator<(node x){
	 	for(int i=0;i<3;i++){
	 		for(int j=0;j<3;j++){
	 			if(a[i][j]<x.a[i][j]){
	 				return true;
	 			}
	 		}
	 	}
	 	return false;
	 }//判断状态相等 
	//node q<node w ---->q.operator(w)
	 bool operator==(node x){
	 	for(int i=0;i<3;i++){
	 		for(int j=0;j<3;j++){
	 			if(a[i][j]!=x.a[i][j]){
	 				return false;
	 			}
	 		}
	 	}
	 	return true;
	 }
	 int tonum(){
	 	int temp=0;
	 	for(int i=0;i<3;i++){
	 		for(int j=0;j<3;j++){
	 			temp=temp*10+a[i][j];
	 		}
	 	}
	 	return temp;
	 }
};
node init;
char input[5];

map<int ,int > m;//存储key(魔方num值):value(到此状态的操作步数) 
node left(node temp,int i){
	int t=temp.a[i][0];
	temp.a[i][0]=temp.a[i][1];
	temp.a[i][1]=temp.a[i][2];
	temp.a[i][2]=t;	
	return temp;
}
node right(node temp,int i){
	int t=temp.a[i][2];
	temp.a[i][2]=temp.a[i][1];
	temp.a[i][1]=temp.a[i][0];
	temp.a[i][0]=t;
	return temp;
}
node up(node temp ,int i){
	int t=temp.a[0][i];
	temp.a[0][i]=temp.a[1][i];
	temp.a[1][i]=temp.a[2][i];
	temp.a[2][i]=t;
	return temp;
}
node down(node temp ,int i){
	int t=temp.a[2][i];
	temp.a[2][i]=temp.a[1][i];
	temp.a[1][i]=temp.a[0][i];
	temp.a[0][i]=t;
	return temp;
}

int bfs(node st){
	queue<node>q;
	q.push(st);
	m[st.tonum()]=0;
	
	while(!q.empty()){
		node a=q.front();
		q.pop();
		if(a==init){
			return 	m[a.tonum()] ;
		}
		node temp;
		for(int i=0;i<3;i++){
			temp=left(a, i);
			if(!m.count(temp.tonum())){
				m[temp.tonum()]=m[a.tonum()]+1;
				q.push(temp);
			}	
		}
		for(int i=0;i<3;i++){
			temp=right( a,i);
			if(!m.count(temp.tonum())){
				m[temp.tonum()]=m[a.tonum()]+1;
				q.push(temp);
			}	
		}
		for(int i=0;i<3;i++){
			temp=up( a, i);
			if(!m.count(temp.tonum())){
				m[temp.tonum()]=m[a.tonum()]+1;
				q.push(temp);
			}	
		}
		for(int i=0;i<3;i++){
			temp=down( a,i);
			if(!m.count(temp.tonum())){
				m[temp.tonum()]=m[a.tonum()]+1;
				q.push(temp);
			}	
		}
		
	}

	
}
int main (){
	
	for(int i=0;i<3;i++){
		for(int j=0;j<3;j++){
			init.a[i][j]=i*3+j+1; //每行基础值是1 2 3 加上3 3 3  
		}
	}
	
	node  st;
	for(int i=0;i<3;i++){
		cin>>input;
		for(int j=0;j<3;j++){
			st.a[i][j]=input[j]-'0';
		}
	} 

	cout<<bfs(st);

	return 0;
} 

【代码分析】用的还是bfs的框架 ,但是记录状态的node需要注意,这时要比较的状态是9个值。

为了判断当前node有没有被访问过,使用bool vis[]就不太方便了,于是用了map,用来存储node的状态值以及一个步骤数;另外map存储struct需要结构体重载<运算符,因为map内部是按照key进行排序的。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值