POJ-3322 Bloxorz I

题目描述

Little Tom loves playing games. One day he downloads a little computer game called 'Bloxorz' which makes him excited. It's a game about rolling a box to a specific position on a special plane. Precisely, the plane, which is composed of several unit cells, is a rectangle shaped area. And the box, consisting of two perfectly aligned unit cube, may either lies down and occupies two neighbouring cells or stands up and occupies one single cell. One may move the box by picking one of the four edges of the box on the ground and rolling the box 90 degrees around that edge, which is counted as one move. There are three kinds of cells, rigid cells, easily broken cells and empty cells. A rigid cell can support full weight of the box, so it can be either one of the two cells that the box lies on or the cell that the box fully stands on. A easily broken cells can only support half the weight of the box, so it cannot be the only cell that the box stands on. An empty cell cannot support anything, so there cannot be any part of the box on that cell. The target of the game is to roll the box standing onto the only target cell on the plane with minimum moves.

在这里插入图片描述

The box stands on a single cell

The box lies on two neighbouring cells, horizontally

The box lies on two neighbouring cells, vertically

The box lies on two neighbouring cells, vertically After Little Tom passes several stages of the game, he finds it much harder than he expected. So he turns to your help.

Bloxorz是一个风靡世界的小游戏。Bloxorz的地图是一个N行M列的矩阵,每个位置可能是硬地(用.表示)、易碎地面(用E表示)、禁地(用#表示)、起点(用X表示)或终点(用O表示)。你的任务是操作一个112的长方体。这个长方体在地面上有两种放置形式,“立”在地面上(11的面接触地面)或者“躺”在地面上(12的面接触地面)。在每一步操作中,可以按上下左右四个键之一。按下之后,长方体向对应的方向沿着棱滚动90度。任意时刻,长方体不能有任何部位接触禁地(否则就会掉下去),并且不能立在易碎地面上(否则会因为压强太大掉下去)。X标识长方体的起始位置,地图上可能有一个X或者两个相邻的X。地图上唯一的一个O标识目标位置。求把长方体移动到目标位置(即立在O上)所需要的最少步数。如果无解,输出Impossible。在移动过程中,X和O标识的位置都可以看作是硬地被利用,3<=N,M<=500。

输入格式

Input contains multiple test cases. Each test case is one single stage of the game. It starts with two integers R and C(3 ≤ R, C ≤ 500) which stands for number of rows and columns of the plane. That follows the plane, which contains R lines and C characters for each line, with 'O' (Oh) for target cell, 'X' for initial position of the box, '.' for a rigid cell, '#' for a empty cell and 'E' for a easily broken cell. A test cases starts with two zeros ends the input.

It guarantees that

There's only one 'O' in a plane.

There's either one 'X' or neighbouring two 'X's in a plane.

The first(and last) row(and column) must be '#'(empty cell).

Cells covered by 'O' and 'X' are all rigid cells.

输出格式

For each test cases output one line with the minimum number of moves or "Impossible" (without quote) when there's no way to achieve the target cell.

样例

样例输入

复制7 7
#######
#..X###
#..##O#
#....E#
#....E#
#.....#
#######
0 0

样例输出

复制10

 做题感想,这道题差点把我写颓废了,写了整整一个下午啊啊啊啊,由于个人太弱,一直调不出来是什么鬼,等我交的时候别人都做完了QAQ。

解题思路:其实思路比较简单,就像普通的bfs一样,但是细节有点多,而且代码量不够的人(比如我)写起来超级浪费时间。首先我们要明白,这个方块有三种躺着的方式,我们选择其中xy坐标最小的一个格子作为代表,然后算出方块利用四条边缘移动后的位置和状态:具体的,有x坐标位置,y坐标位置,z状态,其中,x + rx[z][j],y + ry[z][j], z = rz[z][j]分别表示状态原本在xy点的状态为z的点,移动rx[z][j], ry[z][j]后的状态变为rz[z][j],这里的z有三种分别对应0表示立着,1表示横着躺,2表示竖着躺 ,j有四种,分别是四条边缘。

然后我们不断根据题意判断这个点移动后是否满足条件,再次不断bfs,至于初始点的处理妙处,比较简单,详见代码O^O

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std ;
const int MAXN = 600 ;
int rx[4][5] = {{0, 0, -2, 1}, {0, 0, 1, -1}, {-1, 2, 0, 0} } ;//表示状态为i(第一维)的四种边缘x的变化 
int ry[4][5] = {{1, -2, 0, 0}, {-1, 2, 0, 0}, {0 ,0, 1, -1} } ;//y的变化 
int rz[4][5] = {{1, 1, 2, 2}, {0, 0, 1, 1}, {0, 0, 2, 2} } ;//变化后对应的状态(原数下标分别+x+y后状态为z)
//0表示立着,1表示横着躺,2表示竖着躺 */
int n, m, cnt = 0 ;
struct Node
{
	int x, y, z ;
}P[4], e ;
char mp[MAXN][MAXN] ; 
int Vis[MAXN][MAXN][4], flag = 0 ;
queue<Node> q ; 
bool Check(Node a)
{
	if(mp[a.x][a.y] == '#')	return false ;
	if(mp[a.x][a.y + 1] == '#' && a.z == 1)	return false ;
	if(mp[a.x + 1][a.y] == '#' && a.z == 2)	return false ;
	if(mp[a.x][a.y] != '.' && a.z == 0)	return false ;
	return true ;	
}
void Scan()
{
	cnt = 0, flag = 0 ;
	for(int i = 1; i <= n; i ++)
	{
		scanf("%s", mp[i] + 1) ;
		for(int j = 1; j <= m; j ++)
		{
			if(mp[i][j] == 'X')
			{
				P[++cnt].x = i, P[cnt].y = j, P[cnt].z = 0 ;
				mp[i][j] = '.' ;
			}
			if(mp[i][j] == 'O')
			{
				e.x = i, e.y = j, e.z = 0 ;
				mp[i][j] = '.' ;
			}
			Vis[i][j][0] = Vis[i][j][1] = Vis[i][j][2] = -1 ;
		} 
	}
}
void BFS()
{
	Node a ;
	a = P[1] ;
	if(cnt == 1)	a.z = 0 ;
	if(cnt == 2)
	{
		if(P[1].y = P[2].y - 1 && P[1].x == P[2].x) a.z = 1 ;
		else a.z = 2 ;
	}
	Vis[a.x][a.y][a.z] = 0 ;
	q.push(a) ;
	while(q.empty() == 0)
	{
		a = q.front() ;
		q.pop() ;
		if(a.x == e.x && a.y == e.y && a.z == 0)
		{
			flag = 1 ;
			printf("%d\n", Vis[a.x][a.y][a.z]) ;
			while(q.empty() == 0)	q.pop() ;
			return ; 
		}
		for(int i = 0; i < 4; i ++)
		{
			Node b ;
			b.x = a.x + rx[a.z][i] ;
			b.y = a.y + ry[a.z][i] ;
			b.z = rz[a.z][i] ;
			if(b.x >= 1 && b.y >= 1 && b.x <= n && b.y <= m)
			{
				if(Vis[b.x][b.y][b.z] == -1 && Check(b) == true)
				{
					Vis[b.x][b.y][b.z] = Vis[a.x][a.y][a.z] + 1 ;
					q.push(b) ;
				}
			}
		}
	}
}
int main()
{
	while(scanf("%d%d", &n, &m) != EOF)
	{
		if(n == 0 && m == 0)	return 0 ;
		Scan() ;
		BFS() ;
		if(flag == 0)	printf("Impossible\n") ;
	}
} 

zanzan

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值