Pushing Boxes(队列,广搜)

Imagine you are standing inside a two-dimensional maze composed of square cells which may or may not be filled with rock. You can move north, south, east or west one cell at a step. These moves are called walks.
One of the empty cells contains a box which can be moved to an adjacent free cell by standing next to the box and then moving in the direction of the box. Such a move is called a push. The box cannot be moved in any other way than by pushing, which means that if you push it into a corner you can never get it out of the corner again.

One of the empty cells is marked as the target cell. Your job is to bring the box to the target cell by a sequence of walks and pushes. As the box is very heavy, you would like to minimize the number of pushes. Can you write a program that will work out the best such sequence?

Input
The input contains the descriptions of several mazes. Each maze description starts with a line containing two integers r and c (both <= 20) representing the number of rows and columns of the maze.

Following this are r lines each containing c characters. Each character describes one cell of the maze. A cell full of rock is indicated by a `#' and an empty cell is represented by a `.'. Your starting position is symbolized by `S', the starting position of the box by `B' and the target cell by `T'.

Input is terminated by two zeroes for r and c.

Output
For each maze in the input, first print the number of the maze, as shown in the sample output. Then, if it is impossible to bring the box to the target cell, print ``Impossible.’’.

Otherwise, output a sequence that minimizes the number of pushes. If there is more than one such sequence, choose the one that minimizes the number of total moves (walks and pushes). If there is still more than one such sequence, any one is acceptable.

Print the sequence as a string of the characters N, S, E, W, n, s, e and w where uppercase letters stand for pushes, lowercase letters stand for walks and the different letters stand for the directions north, south, east and west.

Output a single blank line after each test case.

Sample Input

1 7
SB....T
1 7
SB..#.T
7 11
###########
#T##......#
#.#.#..####
#....B....#
#.######..#
#.....S...#
###########
8 4
....
.##.
.#..
.#..
.#.B
.##S
....
###T
0 0

Sample Output

Maze #1
EEEEE

Maze #2
Impossible.

Maze #3
eennwwWWWWeeeeeesswwwwwwwnNN

Maze #4
swwwnnnnnneeesssSSS

在这里插入图片描述

#include<stdio.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include <iostream>
using namespace std;
//若能推动箱子,推之前人的相对坐标和推之后箱子的相对坐标变化
int B[4][2]{ {1,0},{-1,0},{0,1},{0,-1} };//箱子
int M[4][2]{ {-1,0},{1,0},{0,-1},{0,1} };//人
char BX[4] = { 'S','N','E','W' };//箱子对应移动方向
char MX[4] = { 'n','s','w','e' };//人对应移动方向
char map[25][25];//地图
int book[25][25][25][25];//用来记录箱子和人同时移动时是否回到前面所经过的点
int book2[25][25];//用来记录人自己走时是否回到走过的点
int m, n, x_m, y_m, x_b, y_b, x_t, y_t;//人,箱子,终点的初始位置
struct box
{
	int xbox, ybox;
	int xman, yman;
	string str; //string 型字符串
};//推箱子时所用结构体
struct man
{
	int x, y;
	string Str;
};//人单独走时所用结构体
string Bfs(int x, int y, int bx, int by, int ex, int ey)
{
	queue<man>q1;//创建队列
	man v;
	v.Str = "", v.x = x, v.y = y; // 将结构体赋值
	q1.push(v);//加入队列
	memset(book2, 0, sizeof(book2));//初始化数组
	while (!q1.empty())
	{
		man w = q1.front();//取队首
		q1.pop();//丢掉队首
		for (int i = 0; i < 4; i++)
		{
			int tx = w.x + M[i][0];
			int ty = w.y + M[i][1];
			if ((tx == bx && ty == by) || tx<1 || ty<1 || tx>n || ty>m || map[tx][ty] == '#' || book2[tx][ty])//如果走不通
				continue;
			man p;
			p.x = tx, p.y = ty, p.Str = w.Str + MX[i];//储存该路径和此时的坐标
			if (tx == ex && ty == ey)//如果能到达返回该路径
			{
				return p.Str;
			}
			q1.push(p);//加入到队尾
			book2[tx][ty] = 1;//标记已走
		}
	}
	return "no";//如果不能到达
}
void bfs()
{
	book[x_m][y_m][x_b][y_b] = 1;//标记已走 
	queue<box>q;//创建队列 
	box v;
	v.str = "", v.xbox = x_b, v.ybox = y_b, v.xman = x_m, v.yman = y_m;//将结构体赋值
	q.push(v);//将该组结构体数据加入队尾
	int count = 0;
	while (!q.empty())//当队列不为空时
	{
		box w = q.front();//w等于队首
		q.pop();//去掉队首元素
		for (int i = 0; i < 4; i++)
		{
			//人如果要推箱子,必须要在的位置
			int bx = w.xbox + B[i][0];
			int by = w.ybox + B[i][1];
			int mx = w.xbox + M[i][0];
			int my = w.ybox + M[i][1];
			if (bx<1 || by<1 || bx>n || by>m || mx<1 || my<1 || mx>n || my>m || book[mx][my][bx][by] || map[mx][my] == '#' || map[bx][by] == '#')//如果走不通
				continue;
			string S = "";//初始化路径
			if (mx != w.xman || my != w.yman)//如果不在要到达的位置
				S = Bfs(w.xman, w.yman, w.xbox, w.ybox, mx, my);//判断人能否到达想要到的位置
			if (S == "no")
				continue;//如果不能到达该点跳过
			//否则
			book[mx][my][bx][by] = 1;//标记已走 
			box p;
			//将数据存入结构体中 
			p.str = w.str + S + BX[i];
			p.xbox = bx;
			p.ybox = by;
			p.xman = w.xbox;
			p.yman = w.ybox;
			if (bx == x_t && by == y_t)//若可以到达 
			{
				cout << p.str << endl;
				count = 1;
				break;
			}
			if (count)
				break;
			q.push(p);//加入队尾 
		}
		if (count)
			break;
	}
	if(!count)//若不能到达 
		printf("Impossible.\n");
}
int main()
{
	int t = 0;
	while (scanf("%d%d", &n, &m), n != 0 && m != 0)
	{

		memset(book, 0, sizeof(book));//每次循环初始化book数组 
		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= m; j++)
			{
				scanf(" %c", &map[i][j]);
				//记录人,箱子,终点的位置 
				if (map[i][j] == 'T')
				{
					x_t = i; y_t = j;
				}
				if (map[i][j] == 'S')
				{
					x_m = i; y_m = j;
				}
				if (map[i][j] == 'B')
				{
					x_b = i; y_b = j;
				}
			}
		}
		printf("Maze #%d\n", ++t);
		bfs();
		printf("\n");
	}
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值