Push Box
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/65535 K (Java/Others)Total Submission(s): 1167 Accepted Submission(s): 459
Problem Description
Push Box is a classic puzzle game. This game play in a grid, there are five types of block in it, the player, the box, the hole, empty place, and the wall. In every step, player can move up, down, left, or right, if the target place is empty. Moreover, if a box in the target place, and the next place in that direction is empty, player can move to the target place, and then push the box to the next place. Remember, both of the player and boxes can't move out of the grid, or you may assume that there is a wall suround the whole grid. The objective of this game is to push every box to a hole. Now, your problem is to find the strategy to achieve the goal with shortest steps, supposed there are exactly three boxes.
Input
The input consists of several test cases. Each test case start with a line containing two number, n, m(1 < n, m ≤ 8), the rows and the columns of grid. Then n lines follow, each contain exact m characters, representing the type of block in it. (for empty place, X for player, * for box, # for wall, @ for hole). Each case contain exactly one X, three *, and three @. The input end with EOF.
Output
You have to print the length of shortest strategy in a single line for each case. (-1 if no such strategy)
Sample Input
4 4 .... ..*@ ..*@ .X*@ 6 6 ...#@. @..*.. #*##.. ..##*# ..X... .@#...
Sample Output
7 11
Source
【题意】:给三个箱子和三个目的地和人的位置,要求算出人经过的最短步数将三个箱子推到目的地
【思路】:最短,所以用BFS,以人为中心,将人BFS,如果下一步能碰到箱子,再判断箱子的下一个位置能否到达(即那个位置是否合法或者有没别的箱子)
【收获】:用结构体将人和箱子的状态都放进去,这样每个结构体都表示一个完整的状态,对结构体进行BFS,包括上一道推箱子也是这么做的
另外,因为有三个箱子和一个人的位置,所以开一个8维数组来记录是否来过。
【代码】:
#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<cstdlib>
#include<algorithm>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<set>
#include<vector>
#define F first
#define S second
#define PI acos(-1.0)
#define E exp(1.0)
#define INF 0xFFFFFFF
#define MAX -INF
#define len(a) (__int64)strlen(a)
#define mem0(a) (memset(a,0,sizeof(a)))
#define mem1(a) (memset(a,-1,sizeof(a)))
using namespace std;
template<class T> T gcd(T a, T b) {
return b ? gcd(b, a % b) : a;
}
template<class T> T lcm(T a, T b) {
return a / gcd(a, b) * b;
}
template<class T> inline T Min(T a, T b) {
return a < b ? a : b;
}
template<class T> inline T Max(T a, T b) {
return a > b ? a : b;
}
struct node {
int x, y;
};
struct pp {
node a[4];
int step;
} ed, st;
int n, m;
char mp[10][10];
bool vis[8][8][8][8][8][8][8][8];
bool aim[9][8];
int dx[] = { 1, -1, 0, 0 };
int dy[] = { 0, 0, 1, -1 };
bool ok(pp e) //判断是否完整任务
{
int i;
for (i = 0; i < 3; i++) {
if (!aim[e.a[i].x][e.a[i].y])
return 0;
}
return 1;
}
bool judge(int x, int y) //位置合法性判断
{
if (x < 0 || y < 0 || x >= n || y >= m || mp[x][y] == '#')
return 0;
return 1;
}
int bfs() {
pp now;
mem0(vis);
mem0(aim);
st.step = 0;
queue<pp> q;
q.push(st);
for (int i = 0; i < 3; i++) {
aim[ed.a[i].x][ed.a[i].y] = 1; //三个目的地
}
while (!q.empty()) {
now = q.front();
q.pop();
if (ok(now)) //每从队首取出一个状态就判断一次
{
return now.step;
}
if (vis[now.a[0].x][now.a[0].y][now.a[1].x][now.a[1].y][now.a[2].x][now.a[2].y][now.a[3].x][now.a[3].y])
continue;//如果访问过就不在访问
vis[now.a[0].x][now.a[0].y][now.a[1].x][now.a[1].y][now.a[2].x][now.a[2].y][now.a[3].x][now.a[3].y] =
true;
for (int i = 0; i < 4; i++) {
int Nx = now.a[3].x + dx[i];//a[3]表示人的当前位置
int Ny = now.a[3].y + dy[i];//Nx,Ny表示人的下一个位置
if (judge(Nx, Ny)) {
int j;
for (j = 0; j < 3; j++) {//判断下一个位置是否有箱子
if (Nx == now.a[j].x && Ny == now.a[j].y)
break;
}
if (j < 3) {//下一位置有箱子
if (judge(Nx + dx[i], Ny + dy[i]) == 0)
continue;
int k;
for (k = 0; k < 3; k++) {//箱子是否合法以及能不能被推动
if (now.a[k].x == Nx + dx[i]
&& now.a[k].y == Ny + dy[i])
break;
}
if (k == 3) {//下一个状态入队
pp nex = now;
nex.a[j].x = Nx + dx[i];
nex.a[j].y = Ny + dy[i];
nex.step++;
nex.a[3].x = Nx;
nex.a[3].y = Ny;
q.push(nex);
}
} else {//下一位置没箱子
pp nex = now;
nex.step++;
nex.a[3].x = Nx;
nex.a[3].y = Ny;
q.push(nex);
}
}
}
}
return -1;
}
int main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
while (scanf("%d%d", &n, &m) != EOF) {
int n1 = 0;
int n2 = 0;
for (int i = 0; i < n; i++) {
scanf("%s", mp[i]);
for (int j = 0; j < m; j++) {
if (mp[i][j] == 'X') {
st.a[3].x = i;
st.a[3].y = j;
}
if (mp[i][j] == '*') {
st.a[n1].x = i;
st.a[n1++].y = j;
}
if (mp[i][j] == '@') {
ed.a[n2].x = i;
ed.a[n2++].y = j;
}
if (mp[i][j] != '#')
mp[i][j] = '.';
}
}
printf("%d\n", bfs());
}
return 0;
}