【UVALive】2147 - Push!!(bfs+dfs+优先队列)

来源:互联网 发布:手机卡能注册几个淘宝 编辑:程序博客网 时间:2024/06/05 22:52

点击打开题目

2147 - Push!!

Time limit: 3.000 seconds

Mr. Schwarz was a famous powerful pro wrestler. He starts a part time job as a warehouseman. His task is to move a cargo to a goal by repeatedly pushing the cargo in the warehouse, of course, without breaking the walls and the pillars of the warehouse.

There may be some pillars in the warehouse. Except for the locations of the pillars, the floor of the warehouse is paved with square tiles whose size fits with the cargo. Each pillar occupies the same area as a tile.

\epsfbox{p2147.eps}

Initially, the cargo is on the center of a tile. With one push, he can move the cargo onto the center of an adjacent tile if he is in proper position. The tile onto which he will move the cargo must be one of (at most) four tiles (i.e., east, west, north or south) adjacent to the tile where the cargo is present.

To push, he must also be on the tile adjacent to the present tile. He can only push the cargo in the same direction as he faces to it and he cannot pull it. So, when the cargo is on the tile next to a wall (or a pillar), he can only move it along the wall (or the pillar). Furthermore, once he places it on a corner tile, he cannot move it anymore.

He can change his position, if there is a path to the position without obstacles (such as the cargo and pillars) in the way. The goal is not an obstacle. In addition, he can move only in the four directions (i.e., east, west, north or south) and change his direction only at the center of a tile.

As he is not so young, he wants to save his energy by keeping the number of required pushes as small as possible. But he does not mind the count of his pedometer, because walking is very light exercise for him.

Your job is to write a program that outputs the minimum number of pushes required to move the cargo to the goal, if ever possible.

Input 

The input consists of multiple maps, each representing the size and the arrangement of the warehouse. A map is given in the following format.


wh   d11d12d13...d1wd21d22d23...d2w  ...  dh1dh2dh3...dhw


The integers w and h are the lengths of the two sides of the floor of the warehouse in terms of widths of floor tiles.w and h are less than or equal to 7. The integer dij represents what is initially on the corresponding floor area in the following way.

0:
nothing (simply a floor tile)
1:
pillar
2:
the cargo
3:
the goal
4:
the warehouseman (Mr. Schwarz)

Each of the integers 2, 3 and 4 appears exactly once as dij in the map. Integer numbers in an input line are separated by at least one space character. The end of the input is indicated by a line containing two zeros.

Output 

For each map, your program should output a line containing the minimum number of pushes. If the cargo cannot be moved to the goal, `-1' should be output instead.

Sample Input 

5 50 0 0 0 04 2 0 1 10 1 0 0 01 0 0 0 31 0 0 0 05 34 0 0 0 02 0 0 0 00 0 0 0 37 51 1 4 1 0 0 01 1 2 1 0 0 03 0 0 0 0 0 00 1 0 1 0 0 00 0 0 1 0 0 06 60 0 0 0 0 30 0 0 0 0 00 0 0 0 0 00 0 0 0 0 00 2 0 0 0 04 0 0 0 0 00 0

Sample Output 

5-1118



用 bfs + 优先队列 找是否能推到目的地以及最短时间,找的过程中用数组记录箱子的位置和移动方向,同一个方向移动过来的箱子不能再次移动,但是同一个位置,箱子可以从不同方向移动过来。然后dfs搜索推箱子的人能否到那个位置上去推箱子。仔细点!建议关QQ,关音乐,拉窗帘,关手机去做。


代码如下:

#include <cstdio>#include <cstring>#include <queue>#include <algorithm>using namespace std;int w,h;int endd_x,endd_y;int move_x[] = {0,0,1,-1};int move_y[] = {1,-1,0,0};bool used[10][10][5];//记录箱子从四个方向移动到x,y点:1上,2下,3左,4右int map[10][10];bool mark[10][10];//人物的移动(dfs) bool go;//人物是否能移动到推箱子的位置 int ach_x,ach_y;//人物的目标点 struct node{int x,y,step;int px,py;//推箱子人的位置bool friend operator < (node a , node b){return a.step > b.step;}}pr,ne;//以上是所有变量bool check_ach(node a)//是否完成目标 {if (a.x == endd_x && a.y == endd_y)return true;return false;}void dfs(int x,int y){if (go)return;if (x < 1 || x > h || y < 1 || y > w || mark[x][y])return;if (x == ach_x && y == ach_y){go = true;return;}mark[x][y] = true;for (int i = 0 ; i < 4 ; i++)dfs(x + move_x[i] , y + move_y[i]);}bool check_move(node a,int op)//检查能否移动(注意检查的点是未移动的点,第二个参数是移动方向) {int gx,gy,px,py;//箱子要到达的位置,推箱子人要站到的位置gx = a.x + move_x[op];gy = a.y + move_y[op];if (gx < 1 || gx > h || gy < 1 || gy > w || map[gx][gy] == 1 || used[gx][gy][op])return false;//不能移动//再检查推箱子人是否能移动px = a.x - move_x[op];py = a.y - move_y[op];if (px < 1 || px > h || py < 1 || py > w || map[px][py] == 1)//初步检查 return false;//dfs检查 memset (mark,false,sizeof (mark));//true为不能移动的位置 for (int i = 1 ; i <= h ; i++)for (int j = 1 ; j <= w ; j++)if (map[i][j] == 1)mark[i][j] = true;mark[a.x][a.y] = true;go = false;ach_x = px;ach_y = py;dfs(a.px,a.py);if (go)//如果也可以移动到对应推箱子的位置,则可以推 return true;return false;}int bfs(){memset (used,false,sizeof (used));priority_queue<node> Q;pr.step = 0;Q.push(pr);while (!Q.empty()){pr = Q.top();Q.pop();if (check_ach(pr))//先检查是否完成了目标 return pr.step;for (int i = 0 ; i < 4 ; i++)//否则考虑往四个方向移动{if (check_move(pr,i))//检查能否移动{ne.x = pr.x + move_x[i];ne.y = pr.y + move_y[i];ne.px = pr.x;ne.py = pr.y;ne.step = pr.step + 1;used[ne.x][ne.y][i] = true;//能了标记这样移动过Q.push(ne);}}}return -1;}int main(){int ans;while (~scanf ("%d %d",&w,&h) && (w || h)){for (int i = 1 ; i <= h ; i++){for (int j = 1 ; j <= w ; j++){scanf ("%d",&map[i][j]);if (map[i][j] == 3){endd_x = i;endd_y = j;}else if (map[i][j] == 4){pr.px = i;pr.py = j;}else if (map[i][j] == 2){pr.x = i;pr.y = j;}}}ans = bfs();if (ans == -1)printf ("-1\n");elseprintf ("%d\n",ans);}return 0;}


0 0
原创粉丝点击