【ybtoj】【BFS】【例题3】立体推箱子

【例题3】立体推箱子


Link

传送门
题目


解题思路

记录状态时将坐标和木块状态一起记录 ( q [ x ] [ y ] [ t ] ) (q[x][y][t]) (q[x][y][t])
在这里插入图片描述
对于2状态,坐标默认是下面那一块
对于3状态,坐标默认是右边那一块
有几个需要注意的旋转时坐标的改变
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


Code

#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;

const int xw[4][5] = {{}, {-1, 0, 2}, {-2, 0, 1}, {-1, 0, 1}};//把坐标的改变预处理出来
const int yw[4][5] = {{}, {0, 2, 0, -1}, {0, 1, 0, -1}, {0, 1, 0, -2}};
const int tw[4][5] = {{}, {2, 3, 2, 3}, {1, 2, 1, 2}, {3, 1, 3, 1}};
int n, m, s[510][510][5], q[750100][3], h, t, v[510][510][5];
int sx, sy, st, ex, ey, et, ans;
char a[510][510];

void initial() {
	st = 0;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++) {
			if (a[i][j] == 'X' && !st) {
				if (a[i + 1][j] == 'X')//状态2
					sx = i + 1, sy = j, st = 2;
				 else
				if (a[i][j + 1] == 'X')//状态3
					sx = i, sy = j + 1, st = 3;
				 else
				sx = i, sy = j, st = 1;//只有一个‘X’是状态1
			}
			if (a[i][j] == 'O')
				ex = i, ey = j, et = 1;
		}
}

bool check(int x, int y, int t) {
	if (x < 0 || x > n || y < 0 || y > m)
		return 0;
	if (t == 1) {
		if (a[x][y] == 'E' || a[x][y] == '#')//不可以立在易碎地面上
			return 0;
	}
	if (t == 2) {
		if (a[x][y] == '#' || a[x - 1][y] == '#')
			return 0;
	}
	if (t == 3) {
		if (a[x][y] == '#' || a[x][y - 1] == '#')
			return 0;
	}
	return 1;
}

bool BFS() {
	h = t = s[sx][sy][st] = 0;
	q[++t][0] = sx, q[t][1] = sy, q[t][2] = st;
	while (h++ < t) {
		for (int i = 0; i < 4; i++) {
			int xx = q[h][0] + xw[q[h][2]][i];
			int yy = q[h][1] + yw[q[h][2]][i];
			int tt = tw[q[h][2]][i];
			if (check(xx, yy, tt) && //判断当前的(xx, yy, tt)可不可行
				!v[xx][yy][tt]) {//判断(xx, yy, tt)走没走过
				s[xx][yy][tt] = s[q[h][0]][q[h][1]][q[h][2]] + 1;//记录步数
				v[xx][yy][tt] = 1, q[++t][0] = xx, q[t][1] = yy, q[t][2] = tt;
				if (xx == ex && yy == ey && tt == et) {//走到‘O’上
					printf("%d\n", s[ex][ey][et]);
					return 0;
				}
			}
		}
	}
	return 1;
}

int main() {
	scanf("%d%d", &n, &m);
	while (n && m) {
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= m; j++)
				cin>>a[i][j];
		initial();//预处理
		if (BFS())
			printf ("Impossible\n");
		//*****************************************
		ans = 0;
		memset(v, 0, sizeof(v));
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= m; j++)
				a[i][j] = '\0';
		//清空*************************************
		scanf("%d%d", &n, &m);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值