原题处
题目思路:这道题主要是利用广搜解决“走地图”类问题,通过搜索问题状态,从走一步到走多步,最先的得到的结果一定是最小步数。
#include<iostream>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstdio>
#define MAX 510
using namespace std;
int n,m,d[MAX][MAX][3];
char s[MAX][MAX];
int dx[4]={0,0,-1,1},dy[4]={-1,1,0,0};//由于图是按照二维数组保存的
//所以左上角为零点,向下为x轴,向右为y轴
//依次代表左、右、上、下
//i=lie,左右上下依次对应j从0~3,下一步的位置
//如果横着躺,x,y,位于其靠左的位置,此时x相同,y差一
//如果竖着放,x,y位于其靠上的位置,此时y相同,x差一
int next_x[3][4]={{0,0,-2,1},{0,0,-1,1},{0,0,-1,2}};
int next_y[3][4]={{-2,1,0,0},{-1,2,0,0},{-1,1,0,0}};
int next_lie[3][4]={{1,1,2,2},{0,0,1,1},{2,2,0,0}};
struct Rec
{
int x,y,lie;
};
queue<Rec>q;
Rec st,ed;
bool test(int x,int y){
if(x<=0||x>n||y<=0||y>m) return 0;
return 1;
}
bool valid(Rec next){
if(!(test(next.x,next.y))) return 0;
if(s[next.x][next.y]=='#') return 0;//位于禁点
if(next.lie==0&&s[next.x][next.y]!='.') return 0;//站立时,为'#'
if(next.lie==1&&s[next.x][next.y+1]=='#') return 0;
if(next.lie==2&&s[next.x+1][next.y]=='#') return 0;
return 1;
}
void pre(){//寻找并处理起点和终点,‘X’、‘O’变为‘.’,同时针对两个相邻起点按照上述处理,选择靠上还是靠左
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<3;k++){
if(test(i+dx[k],j+dy[k])&&s[i+dx[k]][j+dy[k]]=='X'){
st.x=min(i,i+dx[k]),st.y=min(j,j+dy[k]);
st.lie=k<2?1:2;
s[i][j]='.';
s[i+dx[k]][j+dy[k]]='.';
break;
}
}
if(s[i][j]=='X') st.x=i,st.y=j,st.lie=0;
}
}
}
}
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.size()){
Rec now=q.front();q.pop();
for(int i=0;i<4;i++){
Rec next;
next.x=now.x+next_x[now.lie][i];
next.y=now.y+next_y[now.lie][i];
next.lie=next_lie[now.lie][i];
if(!valid(next)) continue;
if(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){
for(int i=1;i<=n;i++) scanf("%s",s[i]+1);//一次输一行
pre();
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++) cout<<s[i][j]<<" ";
cout<<endl;
}
int ans=bfs();
ans==-1?cout<<"Impossible":cout<<ans;
}
}