HDU 1732 Push Box(BFS)

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值