luogu1126:机器人搬重物:宽搜+地图转换+方向组合

题目连接:该题是luogu试炼场的2-8:T4


题目大意:
1 给出一个0,1棋盘,0表示空格,1表示有柱子。
2 给出机器人的起始坐标和起始方向,给出结束位置,求机器人最少需要多少步数到达;
3 要求1:机器人本身有体积;
4 要求2:机器人消耗步数有以下几种方式:
   1)前进1格;
   2)前进2格;
   3)前进3格;
   4)原地左转(方向改了,位置没变);
   5)原地右转(方向改了,位置没变);


思路分析:迷宫的宽搜的拓展问题:
1 要解决体积问题:如下图分析:地图转换
1.1 黑色坐标系和格子中的灰色,表示题目要求的原始地图;
1.2 蓝色坐标系和交叉点,是机器人中心点实际可以落脚的地方;
1.3 因为机器人有体积,所以红色的交点,都不能到达;
1.4 黄色的线条,是机器人真实的路径。

 2 机器人移动的方向问题:


解题步骤:
1 完成地图转换:
1.1 因为机器人有体积:地图要从格子转换为线的交点;
1.2 机器人的中心点,只能落在上图中蓝色区域的非红色交点上;
1.3 预处理的时候解决两个问题:
    1)封边:机器人有体积,所以不能走边缘; 
    2)封路:障碍格子的四个角,机器人都不能走; 
2 动的方法:
2.1 移动的过程除了要记录位置,还要记录方向;
2.2 移动分两种情况:
    1)向前移动:1,2,3步;
    2)原地转向:
        右转:步数+1;
        左转:步数+1; 
        向后转:步数+2; 


上代码(详细解说):
 

//luogu1126:机器人搬重物
//宽搜+地图转换+方向组合

//地图转换: 
//1 地图要从格子转换为线的交点:因为机器人有体积;
//2 机器人的中心点,只能落在蓝色区域的非红色交点上;
//3 预处理的时候解决两个问题:
//	1)封边:机器人有体积,所以不能走边缘; 
//	2)封路:障碍格子的四个角,机器人都不能走; 

//移动的方法:
//1 移动的过程除了要记录位置,还要记录方向;
//2 移动分两种情况:
//	1)向前移动:1,2,3步;
//	2)原地转向:
//		右转:步数+1;
//		左转:步数+1; 
//		向后转:步数+2; 

//剩下就是宽搜的熟练程度了~ 

#include<bits/stdc++.h>
using namespace std;

int n,m,sx,sy,ex,ey;
char st;
int a[110][110];//线的交汇点:"机器人中心点"能走的地方 

void inp()//输入与地图转换 
{
	scanf("%d %d",&n,&m);//格子地图 
	
	memset(a,0,sizeof(a));//0可以走,-1不能走 
	//封边:因为机器人有体积,不能走最外面的红色框线 
	for(int i=0;i<=n;i++)
	{
		a[i][0]=-1;//左边缘不能走
		a[i][m]=-1;//右边缘不能走 	
	}
	for(int i=0;i<=m;i++)
	{
		a[0][i]=-1;//上边缘不能走 
		a[n][i]=-1;//下边缘不能走 
	}
	
	//封路:将有障碍的格子的四个角(交点)封住 
	for(int i=1;i<=n;i++)//i,j表示格子 
	{
		for(int j=1;j<=m;j++)
		{
			int x;scanf("%d",&x);//原始格子
			if(x>0)//封四角 
			{
				a[i-1][j-1]=-1;//左上角
				a[i-1][j]  =-1;//右上角
				a[i][j-1]  =-1;//左下角
				a[i][j]    =-1;//右下角 
			} 
		}
	}
	//输入(sx,sy),(ex,ey), 初始时st方向 
	scanf("%d %d %d %d %c",&sx,&sy,&ex,&ey,&st);	
}

int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
struct nod{int x,y,t,s;}f[10010];
int tou,wei;
bool b[110][110][5];//对于(x,y)点,t方向是否来过 

void bfs()//宽搜的过程 
{
	//方向预处理方向:
	int tt;//初始方向 
	if(st=='E') tt=0; 	if(st=='S') tt=1;
	if(st=='W') tt=2; 	if(st=='N') tt=3;
	
	//队列初始化
	tou=1;wei=2;
	f[tou].x=sx;  f[tou].y=sy; //坐标 
	f[tou].t=tt;  f[tou].s=0;  // 方向与步数 
	memset(b,0,sizeof(b));
	b[sx][sy][tt]=1;//封路
	 
	//宽搜 
	while(tou<wei)
	{
		int x=f[tou].x;
		int y=f[tou].y;
		int t=f[tou].t;

		//到了终点 
		if(x==ex&&y==ey) { printf("%d",f[tou].s); exit(0); }
		
		//当前方向向前冲:1-3步 
		for(int i=1;i<=3;i++)
		{
			//向前移动 i 步 
			int nx=x+dx[t]*i;
			int ny=y+dy[t]*i;
			
			//边界判断与障碍 
			if(nx<1||nx>=n||ny<1||ny>=m||a[nx][ny]==-1) break;
			//可落脚并且,该方向没来过 
			if(a[nx][ny]==0&&b[nx][ny][t]==0)
			{
				b[nx][ny][t]=1;//封路 
				f[wei].x=nx;
				f[wei].y=ny;
				f[wei].t=t;
				f[wei].s=f[tou].s+1;
				wei++; 
			}
		} 
		
		//原地转向
		for(int i=1;i<=3;i++)//可以转3个方向 
		{
			t++;if(t>3) t=0;
			if(b[x][y][t]==0)//当前点:未试过以这个方向到达 
			{
				b[x][y][t]=1;
				f[wei].x=x;
				f[wei].y=y;
				f[wei].t=t;
				//初始方向和结束方向比较,确定转了几次 
				if(abs(t-f[tou].t)==2) f[wei].s=f[tou].s+2;
				else f[wei].s=f[tou].s+1;
				wei++; 
			}
		}
		tou++;		
	}
	
}
int main()
{
	inp();//输入与地图转换

	//起点或者终点在边框
	if(sx>=n||sx<1||sy>=m||sy<1) 
	{
		printf("-1");return 0;
	} 
	
	//起点或者终点不能落脚
	if(a[sx][sy]==-1||a[ex][ey]==-1) 
	{
		printf("-1");return 0;
	}
	
	bfs();//经典宽搜 
	
	printf("-1");//无解 
	
	return 0;
	
}

猜你喜欢

转载自blog.csdn.net/liusu201601/article/details/89148171
今日推荐