题意:如题所说。
注意:1.要考虑人是否能走到推箱子的地方
2.箱子经过的格子可以再次经过,而箱子经过同一个格子从同一个方向来的只能有一次
3.人不能穿过箱子
解法:BFS+BFS
AC代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//bfs+bfs #include<iostream> #include<queue> using namespace std; #define mem(x,y) memset(x,y,sizeof(x));//牛b的数组初始化,网上学的 const int M=25; int useb[M][M][4],used[M][M];//用作标记useb[][][]之所以是三维数组是因为不单单要标记这一点而是要标记在这点上的方向 int map[M][M];//地图 int n,m;//输入地图的行和列 int bx,by,gx,gy,px,py;// bx,by箱子的坐标 gx,gy目的地的坐标 px,py人的坐标 int nn[4][2]={{0,1},{-1,0},{0,-1},{1,0}};//方向向量:左,上,右,下 int foat;//深搜时用作判断是否能找到该点 struct node//节点 { int bx,by; int px,py; int step; node(int x,int y,int a,int b,int s)//初始化节点 { bx=x,by=y,px=a,py=b,step=s; } const bool operator <(const node &d)//主要作用是用于队列中的元素按step的升序排列 { return step>d.step; } }; bool outside(int x,int y)//判断是否出界 { if(x>0&&x<=n&&y>0&&y<=m&&map[x][y]!=1) return 0; else return 1; } //void dfs(int sx,int sy,int ex,int ey)//悲剧用深搜超时了 //{ // if(sx==ex&&sy==ey) // { // foat=1; // return ; // } // for(int i=0;i<4;i++) // { // int x=sx+nn[i][0]; // int y=sy+nn[i][1]; // if(map[x][y]==1||used[x][y]==1||outside(x,y)) // continue; // else // { // used[x][y]=1; // dfs(x,y,ex,ey); // used[x][y]=0; // } // } //} int dfs ( int sx, int sy, int ex, int ey ) //搜索人能否从一点移动到另一点 { if ( sx == ex && sy == ey ) return 1; queue < int > q; /*int hh[11][11]; */ mem(used,0); //hh[sx][sy] = 1; used[sx][sy]=1; q.push ( sx ), q.push ( sy ); while ( q.size () ) { int x = q.front (); q.pop (); int y = q.front (); q.pop (); for ( int i = 0; i < 4; ++ i ) { int xx = x+nn[i][0], yy = y+nn[i][1]; if ( outside ( xx, yy ) ) continue; if ( !used[xx][yy] ) { if ( xx == ex && yy == ey ) return 1; q.push ( xx ); q.push ( yy ); used[xx][yy] = 1; } } } return 0; } int bfs() { queue<node>q; q.push(node(bx,by,px,py,0)); while(!q.empty()) { node temp=q.front(); q.pop(); if(temp.bx==gx&&temp.by==gy) return temp.step; for(int i=0;i<4;i++)//i<4是因为有四个方向,每一个方向都要判断是否能进队列 { bx=temp.bx+nn[i][0]; by=temp.by+nn[i][1]; px=temp.bx-nn[i][0]; py=temp.by-nn[i][1]; if(outside(bx,by)||outside(px,py)||useb[bx][by][i])//判断是否出界,或在这个方向上走过 continue; map[temp.bx][temp.by]=1;//防止人穿过箱子当前所在的位置 mem(used,0); /*foat=0;*/ if(!dfs(temp.px,temp.py,px,py))//判断人是否能从原来的点移动到所需的点 { map[temp.bx][temp.by]=0;//即使不能到达,也必须还原标记 continue; } map[temp.bx][temp.by]=0;//能到达还原标记 if(bx==gx&&by==gy)//找到 return temp.step+1; q.push(node(bx,by,temp.bx,temp.by,temp.step+1)); useb[bx][by][i]=1; } } return -1; } int main() { int t; cin>>t; while(t--) { map[1][1]=1; mem(useb,0); mem(map,0); int i,j; cin>>n>>m; for(i=1;i<=n;i++) { for(j=1;j<=m;j++) { cin>>map[i][j]; switch(map[i][j]) { case 2:bx=i,by=j;break; case 3:gx=i,gy=j;break; case 4:px=i,py=j;break; } } } cout<<bfs()<<endl; } return 0; } /* 5 6 0 0 0 0 0 3 1 0 1 4 0 1 0 0 1 0 0 1 1 0 2 0 0 1 0 0 0 0 0 1 5 5 0 3 0 0 0 1 0 1 4 0 0 0 1 0 0 1 0 2 0 0 0 0 0 0 0 */