思路
首先这个是广搜。
可以预处理出刚开始的箱子状态和终点。
那么 1 × 2 1\times 2 1×2 的情况怎么记录呢?
我们可以记录第一个格子,然后直接把第二个格子判断状态即可。
然后对于箱子的移动很麻烦,我们要用 d x , d y , d t dx,dy,dt dx,dy,dt 分别表示每种情况下的移动方式。
最后直接搜就好了。
C o d e Code Code
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
const int dx[4][5]={
{
},{
0,0,1,0,-2},{
0,0,1,0,-1},{
0,0,2,0,-1}};
const int dy[4][5]={
{
},{
0,1,0,-2,0},{
0,2,0,-1,0},{
0,1,0,-1,0}};
const int dt[4][5]={
{
},{
0,2,3,2,3},{
0,1,2,1,2},{
0,3,1,3,1}};
int v[510][510][4];
char a[510][510],c;
int n,m,tx,ty;
struct node
{
int x,y,t,c;
}f[10001000];
bool check(int x,int y,int t)
{
if(x<1||x>n||y<1||y>m||v[x][y][t]==1)
return 0;
if(t==1)
{
if(a[x][y]=='E'||a[x][y]=='#')
return 0;
}
if(t==3)
{
if(a[x][y]=='#'||x+1>n||a[x+1][y]=='#')
return 0;
}
if(t==2)
{
if(a[x][y]=='#'||y+1>m||a[x][y+1]=='#')
return 0;
}
return 1;
}
void bfs()
{
int hd=0,tl=1;
while(hd<tl)
{
hd++;
for(int i=1; i<=4; i++)
{
int xx=f[hd].x+dx[f[hd].t][i];
int yy=f[hd].y+dy[f[hd].t][i];
int tt=dt[f[hd].t][i];
if(check(xx,yy,tt))
{
tl++;
f[tl]=(node){
xx,yy,tt,f[hd].c+1};
if(xx==tx&&yy==ty&&tt==1)
{
cout<<f[tl].c<<endl;
return;
}
v[xx][yy][tt]=1;
}
}
}
cout<<"Impossible"<<endl;
}
void ycl()
{
int w=0;
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
{
if(a[i][j]=='X'&&w==0)
{
w=1;
if(a[i][j+1]=='X')
f[1].x=i,f[1].y=j,f[1].t=2;
else if(a[i+1][j]=='X')
f[1].x=i,f[1].y=j,f[1].t=3;
else
f[1].x=i,f[1].y=j,f[1].t=1;
v[i][j][f[1].t]=1;
}
if(a[i][j]=='O')
tx=i,ty=j;
}
}
int main()
{
while(cin>>n>>m)
{
memset(v,0,sizeof(v));
if(n==0&&m==0)
break;
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
{
a[i][j]=getchar();
while(a[i][j]!='#'&&a[i][j]!='X'&&a[i][j]!='.'&&a[i][j]!='O'&&a[i][j]!='E')
a[i][j]=getchar();
}
ycl();
bfs();
}
return 0;
}