【题目】迷宫题的改版,但要求找出到达终点的最少步数。
【题目分析】我们从起点出发,每次往下走最多有四种选择,对应搜索树的一层。使用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进行排序的。