马的遍历(棋盘游戏)

广度优先搜索(Breadth First Search, BFS)类似树的按层次遍历。
原则是:尽可能地先横向搜索;特点是:先访问的顶点其邻接点亦先被访问。
①从顶点v出发,置visited[v]=true,将v入队;
②只要队列不为空,重复将队头u出队,检查u的所有邻接点w,如果visited[u]=false,则将其入队并置visited[u]=true

P1443 马的遍历

传送门

来看题目:

题目描述
有一个n×m的棋盘(1<n,m<=400),在某个点上有一个马,要求你计算出马到达棋盘上任意一个点最少要走几步
输入格式
一行四个数据,棋盘的大小和马的坐标
输出格式
一个n×m的矩阵,代表马到达某个点最少要走几步(左对齐,宽5格,不能到达则输出-1)

看到最短路,首选BFS
因为DFS是一路走到黑,直到走不了再后退一步,一般用来灌水或回溯qwq
注意
①x和y都不要超过边界400
②二维数组的写法(我吐了,visited[x,y]是什么鬼,我居然写出这种东东,免不了某人一番嘲笑hhhhh)
③queue里面可以是一对数值,写法上就是pair
④n行m列,循环输出的时候,内层是到m为止,外层是到n为止(这都能忘我也是佩服自己)
⑤每次注意标明是否来过(visited数组)

#include <bits/stdc++.h>
using namespace std;
queue<pair<int,int> > q;
int step[500][500];
bool visited[500][500];
const int x_gain[] ={-1,-2,-2,-1,1,2,2,1};//用来存放x方向的位移
const int y_gain[] ={2,1,-1,-2,-2,-1,1,2};//用来存放y方向的位移
int main(){
	memset(step,-1,sizeof(step));//注意memset用法
	memset(visited,false,sizeof(visited));
	int n,m,x,y;
	cin>>n>>m>>x>>y;
	q.push(make_pair(x,y));//注意push是一对
	step[x][y]=0;
	visited[x][y]=true;
	while(!q.empty()){
		int x_now=q.front().first;
		int y_now=q.front().second;
		q.pop();
		for(int i=0;i<8;i++){
			int xx=x_now+x_gain[i];
			int yy=y_now+y_gain[i];
			if(xx<1||xx>n||yy<1||yy>m||visited[xx][yy]) continue;
			visited[xx][yy]=true;
			step[xx][yy]=step[x_now][y_now]+1;
			q.push(make_pair(xx,yy));
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			printf("%d ",step[i][j]);
		}
		cout<<endl;
	}
	return 0;
}

P1747 好奇怪的游戏

这题基本和上题一致,就不过多说明了。
传送门

题目描述
爱与愁大神坐在公交车上无聊,于是玩起了手机。一款奇怪的游戏进入了爱与愁大神的眼帘:***(游戏名被打上了马赛克)。这个游戏类似象棋,但是只有黑白马各一匹,在点x1,y1和x2,y2上。它们得从点x1,y1和x2,y2走到1,1。这个游戏与普通象棋不同的地方是:马可以走“日”,也可以像象走“田”。现在爱与愁大神想知道两匹马到1,1的最少步数,你能帮他解决这个问题么?
输入格式
第1行:两个整数x1,y1
第2行:两个整数x2,y2
输出格式
第1行:黑马到1,1的步数
第2行:白马到1,1的步数

马既走“日”又走“田”,也无外乎这12种走法:
在这里插入图片描述

其他基本和上题一致,除了退出条件有变化,当x == 1&&y==1的时候输出step[1][1]

#include <bits/stdc++.h>
using namespace std;
queue<pair<int,int> > q;
int step[21][21];
bool visited[21][21];
const int x_gain[] ={-1,-2,-2,-1,1,2,2,1,-2,-2,2,2};//用来存放x方向的位移
const int y_gain[] ={2,1,-1,-2,-2,-1,1,2,2,-2,2,-2};//用来存放y方向的位移
int bfs(int x,int y){
	memset(step,-1,sizeof(step));//注意memset用法
	memset(visited,false,sizeof(visited));
	while(!q.empty()) q.pop();//清空队列
	q.push(make_pair(x,y));//注意push是一对
	step[x][y]=0;
	visited[x][y]=true;
	while(!q.empty()){
		int x_now=q.front().first;
		int y_now=q.front().second;
		q.pop();
		if(x_now==1&&y_now==1) return step[1][1];
		for(int i=0;i<12;i++){
			int xx=x_now+x_gain[i];
			int yy=y_now+y_gain[i];
			if(xx<1||xx>20||yy<1||yy>20||visited[xx][yy]) continue;
			visited[xx][yy]=true;
			step[xx][yy]=step[x_now][y_now]+1;
			q.push(make_pair(xx,yy));
		}
	}
}
int main(){
	int x1,y1,x2,y2;
	cin>>x1>>y1>>x2>>y2;
	cout<<bfs(x1,y1)<<endl;
	cout<<bfs(x2,y2)<<endl;
	return 0;
}

P1746 离开中山路

可以说是一个模板套三道题目了。这题,和前两题都差不多。
唯一的亮点我觉得在于:怎么读一位数字。巧妙运用char只有一位的特点,声明char数组,然后用它来读,美汁汁儿~~
传送门

题目描述
爱与愁大神买完东西后,打算坐车离开中山路。现在爱与愁大神在x1,y1处,车站在x2,y2处。现在给出一个n×n(n<=1000)的地图,0表示马路,1表示店铺(不能从店铺穿过),爱与愁大神只能垂直或水平着在马路上行进。爱与愁大神为了节省时间,他要求最短到达目的地距离(a[i][j]距离为1)。你能帮他解决吗?
输入格式
第1行:一个数 n
第2行~第n+1行:整个地图描述(0表示马路,1表示店铺,注意两个数之间没有空格)
第n+2行:四个数 x1,y1,x2,y2
输出格式
只有1行:最短到达目的地距离

#include <bits/stdc++.h>
using namespace std;
#define maxn 1010
queue<pair<int,int> > q;
int step[maxn][maxn];
bool visited[maxn][maxn];
char Map[maxn][maxn];//亮点所在
int n;
const int x_gain[] ={-1,0,1,0};//用来存放x方向的位移
const int y_gain[] ={0,-1,0,1};//用来存放y方向的位移
int bfs(int x,int y,int d_x,int d_y){//d_x是destination的横坐标,d_y是destination的纵坐标
	memset(step,-1,sizeof(step));//注意memset用法
	memset(visited,false,sizeof(visited));
	while(!q.empty()) q.pop();//清空队列
	q.push(make_pair(x,y));//注意push是一对
	step[x][y]=0;
	visited[x][y]=true;
	while(!q.empty()){
		int x_now=q.front().first;
		int y_now=q.front().second;
		q.pop();
		if(x_now==d_x&&y_now==d_y) return step[d_x][d_y];
		for(int i=0;i<4;i++){
			int xx=x_now+x_gain[i];
			int yy=y_now+y_gain[i];
			if(xx<1||xx>n||yy<1||yy>n||visited[xx][yy]||Map[xx][yy]=='1') continue;//=='1'这个判断太妙了!
			visited[xx][yy]=true;
			step[xx][yy]=step[x_now][y_now]+1;
			q.push(make_pair(xx,yy));
		}
	}
}
int main(){
	int x1,y1,x2,y2;
	cin>>n;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++) cin>>Map[i][j];
	cin>>x1>>y1>>x2>>y2;
	cout<<bfs(x1,y1,x2,y2)<<endl;
	return 0;
}

P2298 Mzc和男家丁的游戏

传送门

题目背景
mzc与djn的第二弹。
题目描述
mzc家很有钱(开玩笑),他家有n个男家丁(做过上一弹的都知道)。他把她们召集在了一起,他们决定玩捉迷藏。现在mzc要来寻找他的男家丁,大家一起来帮忙啊!
由于男家丁数目不多,再加上mzc大大的找人【laopo】水平很好,所以一次只需要找一个男家丁。
输入格式
第一行有两个数n,m,表示有n行m列供男家丁躲藏,
之后n行m列的矩阵,‘m‘表示mzc,‘d’表示男家丁,‘#’表示不能走,‘.‘表示空地。
输出格式
一行,若有解:一个数sum,表示找到男家丁的最短移动次数。
若无解:输出“No Way!”。

这题唯一要注意的是无解要注意输出No Way!
然后最开始要找到主人的位置,就行。

#include <bits/stdc++.h>
using namespace std;
#define maxn 2010
queue<pair<int,int> > q;
int step[maxn][maxn];
bool visited[maxn][maxn];
char Map[maxn][maxn];
int n,m;
const int x_gain[] ={-1,0,1,0};//用来存放x方向的位移
const int y_gain[] ={0,-1,0,1};//用来存放y方向的位移
int bfs(int x,int y){
	memset(step,-1,sizeof(step));//注意memset用法
	memset(visited,false,sizeof(visited));
	while(!q.empty()) q.pop();//清空队列
	q.push(make_pair(x,y));//注意push是一对
	step[x][y]=0;
	visited[x][y]=true;
	while(!q.empty()){
		int x_now=q.front().first;
		int y_now=q.front().second;
		q.pop();
		if(Map[x_now][y_now]=='m') return step[x_now][y_now];
		for(int i=0;i<4;i++){
			int xx=x_now+x_gain[i];
			int yy=y_now+y_gain[i];
			if(xx<1||xx>n||yy<1||yy>m||visited[xx][yy]||Map[xx][yy]=='#') continue;
			visited[xx][yy]=true;
			step[xx][yy]=step[x_now][y_now]+1;
			q.push(make_pair(xx,yy));
		}
	}
	return -1;
}
int main(){
	int start_x,start_y;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++){
			cin>>Map[i][j];
			if(Map[i][j]=='d'){
				start_x=i;
				start_y=j;
			}
		}
	int res = bfs(start_x,start_y);
	if(res==-1) cout<<"No Way!"<<endl;
	else cout<<res<<endl;
	return 0;
}

在这里插入图片描述

做了这么多题目了,该总结模板了,虾面就是广搜的模板:

int bfs(int x,int y)
{
  q.push(make_pair(x,y)); //起点加入队列
  vis[x][y]=true; //标记
  while(!q.empty()) {
      xx=q.front().first;
      yy=q.front().second; //获取起始坐标
      q.pop(); //弹出队列
      if(符合条件) return ans(答案); 
      for(int i=0;i<走法;i++)
      {
          tx=xx+dx[i];
          ty=yy+dy[i];
          if(符合条件) continue;
          if(符合条件) continue; //符合条件跳过循环
          /*
                         可行,执行该部分语句
                                                    */
          q.push(make_pair(tx,ty)); //加入队列
      }
  }
}

猜你喜欢

转载自blog.csdn.net/weixin_43905108/article/details/106903149
今日推荐