大家一定玩过“推箱子”这个经典的游戏。具体规则就是在一个N*M的地图上,有1个玩家、1个箱子、1个目的地以及若干障碍,其余是空地。玩家可以往上下左右4个方向移动,但是不能移动出地图或者移动到障碍里去。如果往这个方向移动推到了箱子,箱子也会按这个方向移动一格,当然,箱子也不能被推出地图或推到障碍里。当箱子被推到目的地以后,游戏目标达成。现在告诉你游戏开始是初始的地图布局,请你求出玩家最少需要移动多少步才能够将游戏目标达成。 

输入描述:

每个测试输入包含1个测试用例
第一行输入两个数字N,M表示地图的大小。其中0<N,M<=8。
接下来有N行,每行包含M个字符表示该行地图。其中 . 表示空地、X表示玩家、*表示箱子、#表示障碍、@表示目的地。
每个地图必定包含1个玩家、1个箱子、1个目的地。

输出描述:

输出一个数字表示玩家最少需要移动多少步才能将游戏目标达成。当无论如何达成不了的时候,输出-1。

输入例子1:

4 4
....
..*@
....
.X..
6 6
...#..
......
#*##..
..##.#
..X...
.@#...

输出例子1:

3
11

基本方法:bfs搜索,剪枝方法是使用一个数组保存每一种状态,如果某一种状态在先前已经被经历过了,则

这个状态就直接抛弃。

#include<iostream>
#include<stdio.h>
#include<vector>
#include<queue>
#include<math.h>

using namespace std;
struct state
{
	int px, py;	//玩家坐标
	int bx, by;	//箱子坐标
	int step;
	state(int x, int y, int s, int t) : px(x), py(y), bx(s), by(t), step(0) {}
	state update(int dx, int dy, vector<vector<char>>& Map)
	{
		state s(px + dx, py + dy, bx, by);
		s.step = this->step + 1;
		//如果玩家位置与箱子位置重合,更新箱子位置
		if (s.px == s.bx && s.py == s.by)
		{
			s.bx += dx;
			s.by += dy;
		}
		int n = Map.size(), m = Map[0].size();
		if (s.px < 0 || s.px >= n || s.py < 0 || s.py >= m || s.bx < 0 || s.bx >= n || s.by < 0 || s.by >= m)
		{
			s.step = -1;
			return s;
		}
		if (Map[s.bx][s.by] == '#' || Map[s.px][s.py] == '#')
		{//撞墙
			s.step = -1;
		}

		return s;
	}
};
int* setMap(vector<vector<char>>& Map, int n, int m)
{
	int *index = new int[6];
	for (int i = 0; i < n; ++i)
	{
		for (int j = 0; j < m; ++j)
		{
			cin >> Map[i][j];
			switch (Map[i][j])
			{
			case 'X':
				index[0] = i;
				index[1] = j;
				break;
			case '*':
				index[2] = i;
				index[3] = j;
				break;
			case '@':
				index[4] = i;
				index[5] = j;
				break;
			}
		}
	}
	return index;
}
void debug(vector<vector<char>>& Map)
{
	int n = Map.size(), m = Map[0].size();
	for (int i = 0; i < n; ++i)
	{
		for (int j = 0; j < m; ++j)
			cout << Map[i][j] << " ";
		cout << endl;
	}
}
int main()
{
	const int wx[4] = { 0, 1, 0, -1 };
	const int wy[4] = { 1, 0, -1, 0 };
	int n, m;
	cin >> n >> m;
	vector<vector<char>> Map(n, vector<char>(m, 0));
	int *where = setMap(Map, n, m);	//存储初始玩家、初始箱子、终点位置
	//状态数组
	bool flag[10][10][10][10];	//true表示可访问
	//这里使用memset笔试的编译器会报错,可以使用4层vector初始化
	memset(flag, true, sizeof(flag));
	queue<state> que;
	//初始化数据
	flag[where[0]][where[1]][where[2]][where[3]] = false;
	que.push(state(where[0], where[1], where[2], where[3]));
	//bfs
	while (!que.empty())
	{//取出一个状态
		state s = que.front();
		que.pop();
		//该状态是否是终态
		if (s.bx == where[4] && s.by == where[5])
		{
			cout << s.step << endl;
			delete[] where;
			system("pause");
			return 0;
		}
		//向四个方向移动
		for (int i = 0; i < 4; ++i)
		{
			state ns = s.update(wx[i], wy[i], Map);
			if (ns.step != -1 && flag[ns.px][ns.py][ns.bx][ns.by])
			{
				flag[ns.px][ns.py][ns.bx][ns.by] = false;
				que.push(ns);
			}
		}
	}
	cout << -1 << endl;
	delete[] where;
	system("pause");
	return 0;
}

 

10-07 15:33