传送门:
http://acm.hdu.edu.cn/showproblem.php?pid=1254
推箱子
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 9942 Accepted Submission(s): 2920
现在给定房间的结构,箱子的位置,搬运工的位置和箱子要被推去的位置,请你计算出搬运工至少要推动箱子多少格.
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
从人为起点开始bfs,如果人走的下一步是箱子所在的坐标,说明找到了箱子,
箱子的坐标为当前所搜方向上人的坐标前进一格(就是推一格箱子,箱子前进的方向和人前进的方向是一致的),
判断箱子是否到达了目的地,如果是则输出箱子移动的最少步数,到不了就输出-1。
应该按照所走步数多少决定出队列顺序,所以用优先队列处理下。
(人从起点找箱子是不计数的)
需要注意的地方:
1.要判断人的位置是不是合法:有没有越界或者该位置是墙
2.要判断能不能推箱子:也就是人有没有找到箱子,比较一开始人和箱子是由距离的,
如果人走的下一步是箱子所在的坐标,说明找到了箱子
3.要判断箱子位置的合法性:越界或者该点是墙
具有做法:
先将箱子位置和人位置入队
1.如果箱子到了指定位置,直接输出步数
2.四个方向搜,先判断人的下一步位置是否合法,合法的话让人一直走,走到人能推箱子的时候
,在判断推导箱子之后箱子的位置合不合法,合法的话步数加1
具体请参考代码:
code:
#include<bits/stdc++.h>
using namespace std;
int dir[][]= {,,,,,-,-,}; //方向数组
#define max_v 12
int n,m;
int G[max_v][max_v];//存图
int vis[max_v][max_v][max_v][max_v];
struct node
{
int x,y;//人的坐标
int bx,by;//箱子的坐标
int step;//推箱子的步数
bool friend operator<(const node &a, const node &b)
{
//必须优先队列,步数小优先ye1js
return a.step>b.step;
} } start; //起点
bool check_person(node next)//判断人的位置是否合法
{
if(next.x>=&&next.x<=n&&next.y>=&&next.y<=m&&G[next.x][next.y]!=)//没有越界且不是墙
return true;
else
return false;
}
bool check_box1(node next,node t)//判断能不能推箱子
{
if(next.x==t.bx&&next.y==t.by)//如果人走的下一步是箱子所在的坐标,说明找到了箱子
return true;
else
return false;
}
int check_box2(int tbx,int tby)//判断箱子坐标的合法性
{
if(tbx>=&&tbx<=n&&tby>=&&tby<=m&&G[tbx][tby]!=)//越界或者墙
return true;
else
return false;
}
void bfs()
{
node next,t;
priority_queue<node>q;
memset(vis,,sizeof(vis));//标志位置空
//队列初始化
vis[start.x][start.y][start.bx][start.by]=;
start.step=;
q.push(start); while(!q.empty())
{
t=q.top();
q.pop();
if(G[t.bx][t.by]==)//箱子到了指定位置
{
cout<<t.step<<endl;
return ;
} for(int i=; i<; i++)
{
next.x=t.x+dir[i][];//人的下一步
next.y=t.y+dir[i][]; if(check_person(next))//判断人的下一步位置是否合法
{
next.bx=t.bx;//不能推箱子时,箱子的坐标
next.by=t.by;
next.step=t.step; if(check_box1(next,t))//能推箱子
{
int tbx=t.bx+dir[i][];//推动箱子之后,箱子的坐标
int tby=t.by+dir[i][]; if(check_box2(tbx,tby))//判断推导箱子之后箱子坐标的合法性,合法则更新坐标
{
next.bx=tbx;
next.by=tby;
next.step++;//步数加1
}
}
if(vis[next.x][next.y][next.bx][next.by]==)//该情况没有搜过,则入队,开始搜
{
vis[next.x][next.y][next.bx][next.by]=;
q.push(next);
}
}
}
}
cout<<"-1"<<endl;
return ;
}
int main()
{
int t;
cin>>t;
while(t--)
{
cin>>n>>m;
for(int i=; i<=n; i++)
{
for(int j=; j<=m; j++)
{
cin>>G[i][j];
if(G[i][j]==)
{
start.x=i;//找到人在坐标
start.y=j;
G[i][j]=;
}
if(G[i][j]==)
{
start.bx=i;//找到箱子的坐标
start.by=j;
G[i][j]=;
}
}
}
bfs();
}
return ;
}