(POJ 1475) Pushing Boxes (BFS模拟)
Description
Imagine you are standing inside a two-dimensional maze composed of square cells which may or may not be filled with rock. You can move north, south, east or west one cell at a step. These moves are called walks.
One of the empty cells contains a box which can be moved to an adjacent free cell by standing next to the box and then moving in the direction of the box. Such a move is called a push. The box cannot be moved in any other way than by pushing, which means that if you push it into a corner you can never get it out of the corner again.
One of the empty cells is marked as the target cell. Your job is to bring the box to the target cell by a sequence of walks and pushes. As the box is very heavy, you would like to minimize the number of pushes. Can you write a program that will work out the best such sequence?
One of the empty cells contains a box which can be moved to an adjacent free cell by standing next to the box and then moving in the direction of the box. Such a move is called a push. The box cannot be moved in any other way than by pushing, which means that if you push it into a corner you can never get it out of the corner again.
One of the empty cells is marked as the target cell. Your job is to bring the box to the target cell by a sequence of walks and pushes. As the box is very heavy, you would like to minimize the number of pushes. Can you write a program that will work out the best such sequence?
Input
The input contains the descriptions of several mazes. Each maze description starts with a line containing two integers r and c (both <= 20) representing the number of rows and columns of the maze.
Following this are r lines each containing c characters. Each character describes one cell of the maze. A cell full of rock is indicated by a `#' and an empty cell is represented by a `.'. Your starting position is symbolized by `S', the starting position of the box by `B' and the target cell by `T'.
Input is terminated by two zeroes for r and c.
Following this are r lines each containing c characters. Each character describes one cell of the maze. A cell full of rock is indicated by a `#' and an empty cell is represented by a `.'. Your starting position is symbolized by `S', the starting position of the box by `B' and the target cell by `T'.
Input is terminated by two zeroes for r and c.
Output
For each maze in the input, first print the number of the maze, as shown in the sample output. Then, if it is impossible to bring the box to the target cell, print ``Impossible.''.
Otherwise, output a sequence that minimizes the number of pushes. If there is more than one such sequence, choose the one that minimizes the number of total moves (walks and pushes). If there is still more than one such sequence, any one is acceptable.
Print the sequence as a string of the characters N, S, E, W, n, s, e and w where uppercase letters stand for pushes, lowercase letters stand for walks and the different letters stand for the directions north, south, east and west.
Output a single blank line after each test case.
Otherwise, output a sequence that minimizes the number of pushes. If there is more than one such sequence, choose the one that minimizes the number of total moves (walks and pushes). If there is still more than one such sequence, any one is acceptable.
Print the sequence as a string of the characters N, S, E, W, n, s, e and w where uppercase letters stand for pushes, lowercase letters stand for walks and the different letters stand for the directions north, south, east and west.
Output a single blank line after each test case.
Sample Input
1 7 SB....T 1 7 SB..#.T 7 11 ########### #T##......# #.#.#..#### #....B....# #.######..# #.....S...# ########### 8 4 .... .##. .#.. .#.. .#.B .##S .... ###T 0 0
Sample Output
Maze #1 EEEEE Maze #2 Impossible. Maze #3 eennwwWWWWeeeeeesswwwwwwwnNN Maze #4 swwwnnnnnneeesssSSS
在一张最大20*20的地图中给出箱子,人和目标点的位置,然后求人推箱子到达target点的路径,用东西南北(ewsn)表示,并让沿这条路径推箱子时推动的次数最少(注意首要考虑的是让推动次数最少,次要的才是人走的最短距离,天坑,wa了5发......)
这道题可以用动态规划中的思想来考虑,把推箱子问题拆解成很多个状态,每个状态中人的位置和箱子的位置都不相同。这样对状态进行BFS(因为求最短所以用BFS)。每个状态最多可以转移出4个新状态,即把箱子向东西南北4个方向推。
因为要使箱子移动,人只能站在箱子的反方向,所以要用到第二个BFS来计算当前人的位置是否可以到达要推箱子时的位置。
就这样用两个BFS分别遍历状态和箱子,注意在BFS状态开visit数组的时候,箱子和人站的位置都要考虑在内,所以我用的是四维数组来解决(从没开过这么多维的,好在数据不大(-_-||))
#include<iostream> #include<cstdio> #include<vector> #include<set> #include<map> #include<string.h> #include<cmath> #include<algorithm> #include<queue> #include<stack> #define LL long long #define mod 1000000007 #define inf 0x3f3f3f3f using namespace std; struct point { int px,py,bx,by; int pu; string s; }; struct node{ int x,y; string s; }; string ans; int zuobiao[4][2]={0,-1,0,1,-1,0,1,0}; string dc[4]={"W","E","N","S"}; string cd[4]={"w","e","n","s"}; queue<point> box; int visit[30][30]; int visit_box[30][30][30][30]; char a[30][30]; point b,s,t; int n,m; int tui; bool bfs(int x1,int y1,int x2,int y2,int x3,int y3,string &pin) { // cout << "ok" << endl; //printf("from:(%d ,%d)-->(%d,%d) barr:(%d,%d)",x1,y1,x2,y2,x3,y3); // for(int i=1;i<=n;i++) // { // for(int j=1;j<=m;j++) // { // if(i==x1&&j==y1) // printf("S"); // else if(i==x2&&j==y2) // printf("t"); // else if(i==x3&&j==y3) // printf("B"); // else // printf("."); // } // printf("\n"); // } queue<node> run; memset(visit,0,sizeof(visit)); visit[x1][y1]=visit[x3][y3]=1; node tem; tem.x=x1,tem.y=y1,tem.s=""; run.push(tem); while(!run.empty()) { tem=run.front(); run.pop(); if(tem.x==x2&&tem.y==y2) { pin=tem.s; //printf(": successful\n"); return true; } for(int i=0;i<4;i++) { int x=tem.x+zuobiao[i][0]; int y=tem.y+zuobiao[i][1]; if(a[x][y]!='#'&&visit[x][y]==0) { visit[x][y]=1; node temp; temp.x=x; temp.y=y; temp.s=tem.s+cd[i]; run.push(temp); } } } //printf(": false\n"); return false; } bool box_bfs() { int flag=0; visit_box[b.bx][b.by][b.px][b.py]=1; box.push(b); while(!box.empty()) { b=box.front(); box.pop(); for(int i=0;i<4;i++) { int x1=b.bx+zuobiao[i][0]; int y1=b.by+zuobiao[i][1]; int x2=b.bx-zuobiao[i][0]; int y2=b.by-zuobiao[i][1]; string lujing=""; if(a[x1][y1]!='#'&&a[x2][y2]!='#'&&visit_box[x1][y1][b.bx][b.by]==0) if(bfs(b.px,b.py,x2,y2,b.bx,b.by,lujing)) { //printf("i=%d x1=%d y1=%d x2=%d y2=%d\n",i,x1,y1,x2,y2); visit_box[x1][y1][b.bx][b.by]=1; point tem; tem.bx=x1; tem.by=y1; tem.px=b.bx; tem.py=b.by; tem.s=b.s+lujing+dc[i]; tem.pu=b.pu+1; if(a[x1][y1]=='T') { if(tem.pu<tui) { ans=tem.s; tui=tem.pu; } else if(tem.pu==tui) { if(tem.s.length()<ans.length()) ans=tem.s; } flag=1; } else box.push(tem); } } } if(flag==0) return false; return true; } int main() { int tt=1; while(~scanf("%d%d",&n,&m)) { tui=inf; if(n==0&&m==0) break; for(int i=0;i<30;i++) for(int j=0;j<30;j++) a[i][j]='#'; memset(visit,0,sizeof(visit)); memset(visit_box,0,sizeof(visit_box)); ans=""; for(int i=1;i<=n;i++)//数据读入 { getchar(); for(int j=1;j<=m;j++) { scanf("%c",&a[i][j]); if(a[i][j]=='S') b.px=i,b.py=j,a[i][j]='.'; else if(a[i][j]=='B') b.bx=i,b.by=j,b.s="",a[i][j]='.',b.pu=0;; } } printf("Maze #%d\n",tt++); if(box_bfs()) { cout << ans << endl << endl; } else printf("Impossible.\n\n"); } return 0; }
此地非逐弃者之王座,彼方乃行愿者之归所。无限清澈,星界银波。