题意:
箱子是一个长方体,有立着和躺着两种形态,给定图及各点含义,问从起点到终点的最小步数
思路:
图论最小步数,选择BFS进行求解,不同于常规的搜索的那四个方向,这次是一个长方体滚来滚去,有三种不同的状态,注意一点方向数组不要写错了。其他的详见代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
int n,m;
char mp[550][550];
const int dx[4]={0,0,-1,1},dy[4]={-1,1,0,0};
struct rec {
int x,y,lie;
};
bool in(int x,int y) {
if(x>0&&x<=n&&y>0&&y<=m) return true;
return false;
}
rec st,ed;
queue<rec>q;
int d[550][550][4];
void getSt() {
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
if(mp[i][j] == 'O') {//找终点
ed.x = i;
ed.y = j;
ed.lie = 0;
mp[i][j] = '.';
} else if(mp[i][j] == 'X') {//找起点,可能有两格所以要搜一下四周
for(int k=0;k<4;k++) {
int tx = i+dx[k];
int ty = j+dy[k];
if(in(tx,ty) && mp[tx][ty] == 'X') {//如果找到是两个格子为起点的取最小
st.x = min(tx,i);
st.y = min(ty,j);
st.lie = k<2?1:2;//当k为1或0时枚举到的时上下竖着躺的属于1,另一种属于2
mp[i][j] = mp[tx][ty] = '.';
break;
}
if(mp[i][j] == 'X') {//如果不是两个格子的情况那么碰到的唯一一个x就是起点且是直立的属于0
st.x = i;
st.y = j;
st.lie = 0;
}
}
}
}
}
}
bool check(rec Next) {//下一位置的最大的那边合不合法
if(!in(Next.x,Next.y)) return false;
if(mp[Next.x][Next.y] == '#') return false;//当前位置不行直接返回
if(mp[Next.x][Next.y] != '.' && Next.lie == 0)return false;//直立情况当前位必须合法
if(mp[Next.x][Next.y+1] == '#' && Next.lie == 1) return false;//上下躺平情况下一 行需合法
if(mp[Next.x+1][Next.y] == '#' && Next.lie == 2) return false;// 下一列需合法
return true;
}
int Nextx[3][4] = {{0,0,-2,1},{0,0,-1,1},{0,0,-1,2}};//三种不同放置情况的坐标变化
int Nexty[3][4] = {{-2,1,0,0},{-1,2,0,0},{-1,1,0,0}};
int Nextlie[3][4] = {{1,1,2,2},{0,0,1,1},{2,2,0,0}};
int bfs() {
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
for(int k=0;k<=2;k++) {
d[i][j][k] = -1;//各点的步数初始为-1
}
}
}
while(q.size()) q.pop();
d[st.x][st.y][st.lie] = 0;//起点步数为0
q.push(st);//压入起点
while(q.size()) {//开始广搜
rec now = q.front();//取出队头
q.pop();
for(int i=0;i<4;i++) {
rec Next;
Next.x = now.x + Nextx[now.lie][i];
Next.y = now.y + Nexty[now.lie][i];
Next.lie = Nextlie[now.lie][i];
if(check(Next) && d[Next.x][Next.y][Next.lie] == -1) {
d[Next.x][Next.y][Next.lie] = d[now.x][now.y][now.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];
}
}
}
}
return -1;
}
int main()
{
while(cin>>n>>m &&n&&m) {
for(int i=1;i<=n;i++) scanf("%s",mp[i]+1);
getSt();
int ans = bfs();
if(ans == -1) {
cout<<"Impossible"<<endl;
} else {
cout<<ans<<endl;
}
}
}