【广度优先搜索】P1126 机器人搬重物 题解

P1126 机器人搬重物【普及+/提高】题解

(最近给新来的同学们讲了讲广搜,正好巩固一下,所以最近广搜的题解比较多)

这道题是广搜里面细节很多的一道。

首先,我们要预处理一下输入数据。输入数据只表现了哪些点有障碍物,由于

机器人的形状是一个直径1.6米的球。

所以障碍物上下左右相邻的格子都是无法到达的,同时机器人只能在格子边线上走,而输入数据是按照格子本身来输入的。我们可以使用另外一个二维bool数组map[i][j]表示\((i,j)\)这个点能不能到达。其中\(i,j\)都是从\(0\)开始索引编号的。如果在输入数据中,\((i,j)\)\(1\),那么:

(1)map[i][j]=1;

(2)map[i-1][j]=map[i][j-1]=map[i-1][j-1]=1

你们可以理解为输入数据的矩阵向左上方偏移了一个单位,得到map[i][j],再对四周的格子进行处理。请读者自行画图,感性理解

bool vis[55][55][4];//一个状态(前两维是左边,后一维是面向方向)有没有被访问过
bool map[55][55];//一个点有没有障碍物
//vis和map也可以合起来写成一个数组,这里推荐使用两个。
void init(){
	cin>>n>>m;
	int tmp;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>map[i][j];
			if(map[i][j]){
				map[i-1][j]=map[i][j-1]=map[i-1][j-1]=1;
			}
		}
	}

然后就是最后五个数据,分别用stx,sty,fnx,fny,stface这五个变量存储起来。方向(最后一个数据)是以字符类型输入的,我们可以转换一下,便于之后的处理:

	//(接上一块代码:init())
	char ss;
	cin>>stx>>sty>>fnx>>fny;
	cin>>ss;
	switch(ss){
		case 'E':stface=E;break;case 'W':stface=W;break;
		case 'S':stface=S;break;case 'N':stface=N;break;
	}
}

其中E,W,S,N已经在开头定义,注意一定要根据顺时针或逆时针的顺序排列:

const int E=0,S=1,W=2,N=3;

我们知道,搜索(无论是广搜还是深搜)中,一个很重要的环节就是“状态“。题目明显地告诉我们,机器人的坐标和面向方向可以组成一个状态。当然还有走到这一个状态花费的时间:

struct cond{
	int x,y;
	int face;
	int dist;
};

然后就是广搜的基本函数了。这里一定要注意:

1.执行转向操作时,只要在队头状态的dist基础上减1或加1就可以了(这里也体现出const int E=0,S=1,W=2,N=3;中必须按方向顺时针或逆时针排列的必要性),但是如果dist +or- 1 得到的新的面向方向小于\(0\)或大于\(3\),就必须要转换到\(0 \to 3\)之间的数值,具体表现为\(-4\ or +4\)

2.执行运动操作时,如果机器人向前走一步就遇到了障碍物,那么向前走一步是不可能的了。那向前走两步或是三步呢?很明显更不可能,要不然机器人就穿墙了。我第一次写代码就没有考虑到这点,误认为在向前走一步不合法的情况下,走两步和走三步仍然合法,导致了样例都没过。解决方法是,在扩展状态的循环中,按走一步到走三步的顺序尝试扩展,当发现有不合法状态时直接break

其他就都差不多了,详见代码:

bool ok(int x,int y){
	return (x>0)&&(x<n)&&(y>0)&&(y<m);//是否在地图范围内
}
void bfs(){
	queue<cond> q;
	q.push((cond){stx,sty,stface,0});
	vis[stx][sty][stface]=true;
	while(!q.empty()){
		cond now=q.front();
		q.pop();
		const int x=now.x,y=now.y,face=now.face,d=now.dist;
		if(x==fnx&&y==fny){//目标状态
			cout<<d<<endl;
			return;
		}
		for(int i=1;i<=3;i++){ 
			int nx=x+i*dx[face],ny=y+i*dy[face];
			if(!ok(nx,ny)||map[nx][ny]) break;//注意点2
			else if(!vis[nx][ny][face]){
				vis[nx][ny][face]=true;
				q.push((cond){nx,ny,face,d+1});
			}
		}
		int nface1=face+1,nface2=face-1;
		if(nface1>3) nface1-=4;//注意点1
		if(nface2<0) nface2+=4;
		if(ok(x,y)&&(!vis[x][y][nface1])){
			vis[x][y][nface1]=true;
			q.push((cond){x,y,nface1,d+1});
		}
		if(ok(x,y)&&(!vis[x][y][nface2])){
			vis[x][y][nface2]=true;
			q.push((cond){x,y,nface2,d+1});
		}
	}
	cout<<-1<<endl;
}

AC代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int E=0,S=1,W=2,N=3;
bool vis[55][55][4];
bool map[55][55];
int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
int n,m;
int stx,sty,fnx,fny,stface;
struct cond{
	int x,y;
	int face;
	int dist;
};
void init(){
	cin>>n>>m;
	int tmp;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>map[i][j];
			if(map[i][j]){
				map[i-1][j]=map[i][j-1]=map[i-1][j-1]=1;
			}
		}
	}
	char ss;
	cin>>stx>>sty>>fnx>>fny;
	cin>>ss;
	switch(ss){
		case 'E':stface=E;break;case 'W':stface=W;break;
		case 'S':stface=S;break;case 'N':stface=N;break;
	}
}

bool ok(int x,int y){
	return (x>0)&&(x<n)&&(y>0)&&(y<m);
}
void bfs(){
	queue<cond> q;
	q.push((cond){stx,sty,stface,0});
	vis[stx][sty][stface]=true;
	while(!q.empty()){
		cond now=q.front();
		q.pop();
		const int x=now.x,y=now.y,face=now.face,d=now.dist;
		if(x==fnx&&y==fny){
			cout<<d<<endl;
			return;
		}
		for(int i=1;i<=3;i++){ 
			int nx=x+i*dx[face],ny=y+i*dy[face];
			if(!ok(nx,ny)||map[nx][ny]) break;
			else if(!vis[nx][ny][face]){
				vis[nx][ny][face]=true;
				q.push((cond){nx,ny,face,d+1});
			}
		}
		int nface1=face+1,nface2=face-1;
		if(nface1>3) nface1-=4;
		if(nface2<0) nface2+=4;
		if(ok(x,y)&&(!vis[x][y][nface1])){
			vis[x][y][nface1]=true;
			q.push((cond){x,y,nface1,d+1});
		}
		if(ok(x,y)&&(!vis[x][y][nface2])){
			vis[x][y][nface2]=true;
			q.push((cond){x,y,nface2,d+1});
		}
	}
	cout<<-1<<endl;
}
int main()
{
	ios::sync_with_stdio(false);
	init();
	bfs();
	return 0;
}
posted @ 2020-07-17 11:51  梦中霜雪梨花白  阅读(242)  评论(0编辑  收藏  举报