1. 程式人生 > 其它 >Pushing Boxes(佇列,廣搜)

Pushing Boxes(佇列,廣搜)

技術標籤:搜尋演算法佇列c++c語言

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");
	}
}