• 【广度优先搜索】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 o 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;
    }
    
  • 相关阅读:
    Linux下gdb调试(tui)
    gdb tui中切换窗口
    gdb调试时的问题Missing separate debuginfos, use: debuginfo-install glibc-XXX
    进程间通信
    深入理解计算机系统结构——链接
    系统调用
    模块机制
    其他文件系统
    Oracle数据库逻辑迁移之数据泵的注意事项
    Oracle 10g DG 数据文件迁移
  • 原文地址:https://www.cnblogs.com/jiangyuechen/p/13329035.html
Copyright © 2020-2023  润新知