Bloxorz I [POJ3322]

题面描述
一个游戏,为一个 N N N M M M列第二矩阵,位置可能是硬地(" . . .")、易碎地面(“ E E E”)、禁地("#")、起点(“ X X X”)或终点(“ O O O”).你的任务是操作一个 1 ∗ 1 ∗ 2 1*1*2 112的长方体。这个长方体在地面上有两种放置形式.“立”(占 1 ∗ 1 1*1 11),“躺”(占 1 ∗ 2 1*2 12)。每一步操作中,可以按上下左右四个键之一。按下任意键,可以使长方体向对应方向沿着棱滚动 90 ° 90° 90°
有以下禁忌

  1. 不能有任何部位接触“#”
  2. 不能有立在“ E E E”的情况

图中可能有两个“ X X X”的情况,目标:求出滚动到“ O O O”的步数,如果不能则输出“ I m p o s s i b l e Impossible Impossible
数据范围: 3 ≤ N , M ≤ 500 3≤N,M≤500 3N,M500.

思路
其实挺好想的,就是看自己愿不愿意下功夫
本文代码用了三元组 ( x , y , l i e ) (x,y,lie) (x,y,lie)
来表示当
l i e = 0 lie=0 lie=0时,即为立起来时,位置为 ( x , y ) (x,y) (x,y).
l i e = 1 lie=1 lie=1时,即为横躺着,左半部分的位置为 ( x , y ) (x,y) (x,y).
l i e = 2 lie=2 lie=2时,即为竖躺着,上半部分的位置为 ( x , y ) (x,y) (x,y)
手动模拟一下
得出

const int next_x[3][4]={{0,0,-2,1},{0,0,-1,1},{0,0,-1,2}};
const int next_y[3][4]={{-2,1,0,0},{-1,2,0,0},{-1,1,0,0}};
const int next_lie[3][4]={{1,1,2,2},{0,0,1,1},{2,2,0,0}};

0~3分别表示左、右、上、下方向
解释一下 n e x t x [ i ] [ j ] next_x[i][j] nextx[i][j]即处于 l i e = i    方 向 为 j 滚 动 lie=i~~方向为j滚动 lie=i  j的x增减状态,
以此类推。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstdlib>
using namespace std;
const int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
const int next_x[3][4]={{0,0,-2,1},{0,0,-1,1},{0,0,-1,2}};
const int next_y[3][4]={{-2,1,0,0},{-1,2,0,0},{-1,1,0,0}};
const int next_lie[3][4]={{1,1,2,2},{0,0,1,1},{2,2,0,0}};
struct node
{
	int x,y,lie;//lie==0立着,lie==1横着躺,lie==2竖着躺 
	node(){};
	node(int x,int y,int lie):x(x),y(y),lie(lie){}
};
char s[510][510];
node st,ed;
int n,m,d[510][510][3];
queue<node>q;
bool valid(int x,int y)
{
	return x>=1&&x<=n&&y>=1&&y<=m;
}
bool valid(node next)
{
	if(!valid(next.x,next.y))return 0;
	int x=next.x,y=next.y,lie=next.lie;
	if(s[x][y]=='#')return 0;
	if(s[x][y]!='.'&&!lie)return 0;
	if(lie==1&&s[x][y+1]=='#')return 0;
	if(lie==2&&s[x+1][y]=='#')return 0;
	return 1;
}
void pre()
{
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
		{
			if(s[i][j]=='O')ed.x=i,ed.y=j,ed.lie=0,s[i][j]='.';
			else if(s[i][j]=='X')
			{
				for(int k=0;k<4;k++)
				{
					int x=dx[k]+i,y=dy[k]+j;
					if(s[x][y]=='X'&&valid(x,y))
					{
						st.x=min(i,x),st.y=min(j,y);
						st.lie=k<2?1:2;
						s[i][j]=s[x][y]='.';
						break;
					}
					if(s[i][j]=='X')st.x=i,st.y=j,st.lie=0,s[i][j]='.';
				}
			}
		}
}
int bfs()
{
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			for(int k=0;k<3;k++)d[i][j][k]=-1;
	while(q.size())q.pop();
	d[st.x][st.y][st.lie]=0;q.push(st);
	while(!q.empty())
	{
		node t=q.front();q.pop();
		for(int i=0;i<4;i++)
		{
			node next=t;
			next.x+=next_x[next.lie][i];
			next.y+=next_y[next.lie][i];
			next.lie=next_lie[next.lie][i];
			if(!valid(next))continue;
			if(d[next.x][next.y][next.lie]==-1)
			{
				d[next.x][next.y][next.lie]=d[t.x][t.y][t.lie]+1;
				q.push(next);
				if(next.x==ed.x&&next.y==ed.y&&next.lie==ed.lie)return d[next.x][next.y][next.lie];
			}
			if(d[ed.x][ed.y][ed.lie]!=-1)return d[ed.x][ed.y][ed.lie];
		}
	}
	return -1;
}
int main()
{
	while(scanf("%d%d",&n,&m)&&n)
	{
		for(int i=1;i<=n;i++)scanf("%s",s[i]+1);
		pre();
		int ans=bfs();
		if(ans==-1)puts("Impossible");else printf("%d\n",ans);
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值