【ybtoj 高效进阶 1.5】 【广搜】 立体堆箱子
题目
解题思路
将长方体3种摆放情况记录下来
立着就只记录本身,竖着记录下面的,横着记录右边的
手推这三种情况向上下左右推是哪种状态
经典广搜跑一遍
代码
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
struct lzf{
int x,y,t,b;
}q[1000100];
char c;
int n,m,h,t,zx,zy,a[520][520],p[520][520][4];
int fx[4][5]={
{
},{
0,-1,0,2,0},{
0,-2,0,1,0},{
0,-1,0,1,0}};
int fy[4][5]={
{
},{
0,0,2,0,-1},{
0,0,1,0,-1},{
0,0,1,0,-2}}; //坐标的变化
int ft[4][5]={
{
},{
0,2,3,2,3},{
0,1,2,1,2},{
0,3,1,3,1}}; //状态的变化
bool check(int xx,int yy,int tt)
{
if (xx<1||xx>n||yy<1||yy>m) return 0;
if (tt==1&&a[xx][yy]==0) return 1; //只有一个立着,不可以在易碎面上
if (tt==2&&a[xx][yy]!=1&&a[xx-1][yy]!=1&&xx-1>0) return 1; //竖着,两个都不能是禁地
if (tt==3&&a[xx][yy]!=1&&a[xx][yy-1]!=1&&yy-1>0) return 1; //横着,两个也不能是禁地
return 0;
}
bool dfs()
{
do{
h++;
for (int i=1;i<=4;i++)
{
int xx=q[h].x+fx[q[h].t][i],yy=q[h].y+fy[q[h].t][i],tt=ft[q[h].t][i];
if (check(xx,yy,tt)&&!p[xx][yy][tt]) //可以走,且没走过
{
q[++t].x=xx;
q[t].y=yy;
q[t].t=tt;
q[t].b=q[h].b+1;
p[xx][yy][tt]=1; //进队
if (xx==zx&&yy==zy&&q[t].t==1)
{
printf("%d\n",q[t].b);
return 0;
}
}
}
} while (h<t);
return 1;
}
int main()
{
while (1)
{
scanf("%d%d",&n,&m);
if (!n&&!m) break;
h=0,t=1;
int vis=0;
memset(a,0,sizeof(a));
memset(q,0,sizeof(q));
memset(p,0,sizeof(p));
q[t].t=1;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
cin>>c;
if (c=='#') a[i][j]=1;
if (c=='E') a[i][j]=-1;
if (c=='O') zx=i,zy=j,a[i][j]=0;
if (c=='X')
{
if (vis)
if (q[t].x+1==i&&q[t].x)
q[t].t=2;
else q[t].t=3; //更改起始点的状态
q[t].x=i;
q[t].y=j;
vis=1;
} //预处理
}
p[q[t].x][q[t].y][q[t].t]=1;
if (dfs()) printf("Impossible\n");
}
return 0;
}