题意:地图上分别用‘.’表示硬地,‘#’表示禁地,‘E’表示易碎地面。你的任务操作一个1*1*2的长方体。长方体有两种状态分别为:立在地面上,躺在地面上。把长方体从入口移动到出口,求需要的最小步数。
原题链接:http://poj.org/problem?id=3322
#include<iostream> #include<cstring> #include<queue> #include<cstdio> using namespace std; struct node{ int x; int y; int lie; //lie=0,代表竖着;lie=1,代表横着躺着;lie=2,代表垂直躺着 }; char map[553][553]; int r,c;//r表示地图的行数,c表示地图的列数 node start,end; //记录起点和终点的状态 int dx[4]={-1,1,0,0};//表示左右方向的移动 int dy[4]={0,0,1,-1};//表示上下方向的移动 int dis[553][553][3];//记录起点走到x,y时候,状态为lie的路径长度 void init() { for(int i=1;i<=r;i++) { for(int j=1;j<=c;j++) { for(int k=0;k<3;k++) { dis[i][j][k]=-1; } } } } bool judge(int x,int y) { if(x<=r&&x>=1&&y<=c&&y>=1) { return true; } return false; } bool judge_stay(node n)//判断一个长方体呆着是否合理 { if(!judge(n.x,n.y)) return 0; if(map[n.x][n.y]=='#') return 0; if(n.lie==0&&map[n.x][n.y]!='.') return 0; if(n.lie==1&&(map[n.x][n.y+1]=='#')) return 0; if(n.lie==2&&(map[n.x+1][n.y]=='#')) return 0; return 1; } /* int dx_lie0[4]={0,0,-2,1};//lie=0的时候,向四个方向运动时,x的变化。 左右上下 int dy_lie0[4]={-2,1,0,0};//lie=0的时候,向四个方向运动时,y的变化。 int dx_lie1[4]={0,0,-1,1}; int dy_lie1[4]={-1,2,0,0}; int dx_lie2[4]={0,0,-1,2}; int dy_lie2[4]={-1,1,0,0}; */ int dx_lie[3][4]={0,0,-2,1,0,0,-1,1,0,0,-1,2}; int dy_lie[3][4]={-2,1,0,0,-1,2,0,0,-1,1,0,0}; int lie[3][4]={1,1,2,2,0,0,1,1,2,2,0,0};//lie[i][j]表示状态为i的时候,向j方向反转后,lie的状态 int bfs() { queue<node>q; while(!q.empty()) { q.pop(); } q.push(start); dis[start.x][start.y][start.lie]=0; while(!q.empty()) { node t=q.front(); q.pop(); for(int k=0;k<4;k++) { node next; next.x=t.x+dx_lie[t.lie][k]; next.y=t.y+dy_lie[t.lie][k]; next.lie=lie[t.lie][k]; if(judge_stay(next)) { if(dis[next.x][next.y][next.lie]==-1) { //cout<<t.x<<' '<<t.y<<' '<<t.lie<<endl; //cout<<"x"<<next.x<<endl; //cout<<"y"<<next.y<<endl; //cout<<"lie"<<next.lie<<endl; q.push(next); dis[next.x][next.y][next.lie]=dis[t.x][t.y][t.lie]+1; //cout<<endl<<"x"<<next.x<<" y"<<next.y<<" lie"<<next.lie<<" dis"<<dis[next.x][next.y][next.lie]; //cout<<endl<<endl; if(next.x==end.x&&next.y==end.y&&next.lie==end.lie) { return dis[next.x][next.y][next.lie]; } } } } } return -1; } void fun_st_ed() //处理起点和终点 { for(int i=1;i<=r;i++) { for(int j=1;j<=c;j++) { if(map[i][j]=='O') { end.x=i; end.y=j; end.lie=0; map[i][j]='.'; } if(map[i][j]=='X') { for(int k=0;k<4;k++) { int next_x=i+dx[k]; int next_y=j+dy[k]; if(judge(next_x,next_y)&&map[next_x][next_y]=='X') { start.x=min(i,next_x); start.y=min(j,next_y); start.lie=k<2?2:1;//k<2的时候说明是上下有连着的X,k>2说明左右有连着的X; map[i][j]='.'; map[next_x][next_y]='.'; } } } if(map[i][j]=='X')//说明周围四个点当中没有X。 { //cout<<"i"<<i<<"j"<<j<<endl; start.x=i; start.y=j; start.lie=0; map[i][j]='.'; } } } } int main() { while(cin>>r>>c) { if(r==0&&c==0) { break; } memset(map,0,sizeof(map)); for(int i=1;i<=r;i++) { //for(int j=1;j<=c;j++) //{ //cin>>map[i][j]; scanf("%s",map[i]+1); //} //getchar(); } init(); fun_st_ed(); //cout<<start.x<<start.y<<start.lie<<endl; int ans=bfs(); if(ans==-1) { cout<<"Impossible"<<endl; } else { cout<<ans<<endl; } } return 0; } /* 7 7 ####### #...X## #..##O# #....E# #....E# #.....# ####### */
解题思路:用bfs求最短路径。用数组表示前状态和后状态的关系。用dis数组记录最短路径的长度。