您的位置:首页 > 其它

【杭电oj】1254 - 推箱子(dfs+bfs+优先队列)

2016-07-20 18:00 323 查看
点击打开题目


推箱子

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)

Total Submission(s): 7258    Accepted Submission(s): 2079


Problem Description

推箱子是一个很经典的游戏.今天我们来玩一个简单版本.在一个M*N的房间里有一个箱子和一个搬运工,搬运工的工作就是把箱子推到指定的位置,注意,搬运工只能推箱子而不能拉箱子,因此如果箱子被推到一个角上(如图2)那么箱子就不能再被移动了,如果箱子被推到一面墙上,那么箱子只能沿着墙移动.

现在给定房间的结构,箱子的位置,搬运工的位置和箱子要被推去的位置,请你计算出搬运工至少要推动箱子多少格.



 

Input

输入数据的第一行是一个整数T(1<=T<=20),代表测试数据的数量.然后是T组测试数据,每组测试数据的第一行是两个正整数M,N(2<=M,N<=7),代表房间的大小,然后是一个M行N列的矩阵,代表房间的布局,其中0代表空的地板,1代表墙,2代表箱子的起始位置,3代表箱子要被推去的位置,4代表搬运工的起始位置.

 

Output

对于每组测试数据,输出搬运工最少需要推动箱子多少格才能帮箱子推到指定位置,如果不能推到指定位置则输出-1.

 

Sample Input

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

 

Sample Output

4

 

Author

Ignatius.L & weigang Lee

跟UVALive的题一模一样,给一个传送门,注意两道题的w和h的顺序不同。

传送门:点击打开链接

代码如下:

#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 u;
int ans;
scanf ("%d",&u);
while (u--)
{
scanf ("%d %d",&h,&w);
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");
else
printf ("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: