1 /* 2 *State: HDU1254 31MS 4920K 2558 B C++ 3 *题目大意: 4 * 推箱子,1代表墙,2代表箱子,3代表终点,4代表人。 5 *解题思路: 6 * 要先搜出人可以到达的位置,来判断箱子能否朝这个方向 7 * 前进,之后还要注意一个状态的标志,一个位置可以走四次 8 * 因为有四个不同的方向(这是此题的亮处吧)。 9 *解题感想; 10 * 贡献了好多个wa,就是因为没有想对状态。 11 1.箱子前方没有障碍物; 12 2.箱子后方没有障碍物; 13 3.人能到达箱子后面。 14 15 1)采用DFS/BFS判断人是否可以到达箱子的对面时,要明确人不能穿过箱子,即对箱子标记flag[p.Bx][p.By] = 1; 16 17 (2)求箱子的对面求坐标时要保证这个坐标没有超边界。 18 19 (3)DFS时不需要回溯。 20 21 (4)推箱子时,人的位置不会跟随箱子的移动而移动。 22 */ 23 24 #include <iostream> 25 #include <stdio.h> 26 #include <memory.h> 27 #include <queue> 28 using namespace std; 29 30 int xx[8] = {-1, 0, 1, 0, -1, 0, 1, 0}; 31 int yy[8] = {0, -1, 0, 1, 0, -1, 0, 1}; 32 33 bool map[10][10][5]; //map[][][]三维数组,记录箱子(x,y)坐标和方向 34 int a[10][10], b[10][10], c[10][10]; 35 int x1, y1, x2, y2, tx, ty, px, py, ax, ay; 36 int N, M; 37 bool flag; 38 39 struct node 40 { 41 int x, y, px, py, step; //分别保存箱子的坐标(x,y)、人的坐标(px,py)、步数 42 } n, m; 43 44 bool dfs(int x, int y) //深搜:判断人是否能够到达箱子的后面 45 { 46 if(x == tx && y == ty) return true; //到达箱子后面 47 if(x<0 || x>=N || y<0 || y>=M) return false; //越界的返回false 48 if(x == ax && y == ay) return false; //该点是箱子挡住路了 49 if(b[x][y] == 1) return false; //该点是墙壁挡住路了 50 b[x][y] = 1; //走过的标记不能再走 51 return (dfs(x+1,y) || dfs(x-1,y) || dfs(x,y+1) || dfs(x,y-1)); //往内深搜 52 } 53 54 void set_bc() //初始化深搜时用到的数组b[][] 55 { 56 int i, j; 57 for(i = 0; i < N; i++) 58 for(j = 0; j < M; j++) 59 b[i][j] = c[i][j]; 60 } 61 62 int main() 63 { 64 int i, j, k, t; 65 scanf("%d", &t); 66 while(t--) 67 { 68 scanf("%d %d", &N, &M); 69 for(i = 0; i < N; i++) 70 { 71 for(j = 0; j < M; j++) 72 { 73 cin>>a[i][j]; 74 c[i][j] = b[i][j] = a[i][j]; 75 if(a[i][j] == 2) 76 x1 = i, y1 = j; //箱子的坐标 77 if(a[i][j] == 3) 78 x2 = i, y2 = j; //目标的坐标 79 if(a[i][j] == 4) 80 px = i, py = j; //人的坐标 81 for(k = 0; k < 4; k++) 82 map[i][j][k] = false; //初始化map[][][] 83 } 84 } 85 flag = false; 86 n.x = x1; 87 n.y = y1; 88 n.step = 0; //更新第一个push进去的点 89 n.px = px; 90 n.py = py; 91 queue<node> Q; 92 Q.push(n); 93 while(!Q.empty()) 94 { 95 m = Q.front(); 96 Q.pop(); 97 if(m.x == x2 && m.y == y2) //箱子到达目标 98 { 99 flag = true; 100 break; 101 } 102 for(i = 0; i < 4; i++) 103 { 104 n.x = m.x + xx[i]; //后来箱子的位置 105 n.y = m.y + yy[i]; 106 //i+2 刚好是箱子的反方向位置 107 tx = m.x + xx[i+2]; //后来人的位置 108 ty = m.y + yy[i+2]; 109 ax = m.x; //原来箱子的位置 110 ay = m.y; 111 n.px = m.px; //原来人的位置 112 n.py = m.py; 113 n.step = m.step + 1; 114 if(n.x>=0 && n.x<N && n.y>=0 && n.y<M && !map[n.x][n.y][i] && a[n.x][n.y]!=1) //箱子前方没问题 115 { 116 set_bc(); //初始化b[][]数组 117 if(tx>=0 && tx<N && ty>=0 && ty<M && a[tx][ty]!=1 && dfs(n.px, n.py)) //人能到达箱子的后方 118 { 119 //则箱子能推倒该点(n.px,n.py) 120 n.px = tx; 121 n.py = ty; 122 map[n.x][n.y][i] = true; //标记该点和来的这个i方向 123 Q.push(n); 124 } 125 } 126 } 127 } 128 if(flag) printf("%d\n", m.step); 129 else printf("-1\n"); 130 } 131 132 return 0; 133 }