本题有一定难度,使用双向BFS,一个是从箱子起点到终点的 BFS,一个是从人的位置到推箱子的位置的 BFS。注意记录箱子位置的访问状态要使用三维 vis[i][j][dir],因为从不同的位置推箱子产生的后续状态不同。
#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
int M, N; //地图边长
int mp[10][10]; //地图
int visPeo[10][10], visBox[10][10][4]; //人的位置访问情况,箱子的位置访问情况
int dir[4][2] = { {0,1},{0,-1},{1,0},{-1,0} }; //前进方向
struct status //状态
{
int x, y; //坐标
int step; //步数
int smap[10][10]; //当前状态的地图
bool check() //判断该位置是否在地图内
{
if (x >= 0 && x < M && y >= 0 && y < N)
return true;
else
return false;
}
};
status startBox; //箱子的起始状态
status startPeo; //人的起始状态
status nowPeo; //人的当前状态
//广搜,搜索人能否到达指定位置
bool bfs_people(status s)
{
memset(visPeo, 0, sizeof(visPeo));
queue<status> q;
for (int i = 0; i < M; i++) //查找当前状态的地图中,人的位置
{
for (int j = 0; j < N; j++)
if (s.smap[i][j] == 4)
{
startPeo.x = i;
startPeo.y = j;
startPeo.step = 0;
}
}
if (startPeo.x == nowPeo.x && startPeo.y == nowPeo.y)
return true;
q.push(startPeo);
visPeo[startPeo.x][startPeo.y] = true;
status now, nex;
while (!q.empty())
{
now = q.front();
q.pop();
for (int i = 0; i < 4; i++) //依次搜索4个方向
{
nex.x = now.x + dir[i][0];
nex.y = now.y + dir[i][1];
nex.step = now.step + 1;
if (nex.check() && visPeo[nex.x][nex.y] == 0 &&
s.smap[nex.x][nex.y] != 1 && s.smap[nex.x][nex.y] != 2)
{
visPeo[nex.x][nex.y] = true;
if (nex.x == nowPeo.x && nex.y == nowPeo.y)
return true;
q.push(nex);
}
}
}
return false;
}
//广搜,搜索把箱子从起点推到终点的最小步数
int bfs_box()
{
memset(visBox, 0, sizeof(visBox));
queue<status> q;
q.push(startBox);
status now, nex; //当前状态,下一状态
while (!q.empty())
{
now = q.front();
q.pop();
for (int i = 0; i < 4; i++) //依次搜索4个方向
{
nex = now; //此处为了将now的smap复制给nex
nex.x += dir[i][0];
nex.y += dir[i][1];
nex.step++;
if (nex.check() && mp[nex.x][nex.y] != 1 && visBox[nex.x][nex.y][i] == 0)
{
//想要向当前方向推动箱子,人需要在的位置
nowPeo.x = now.x - dir[i][0];
nowPeo.y = now.y - dir[i][1];
if (nowPeo.check() && bfs_people(nex))
{
//更新地图,箱子和人的位置
swap(nex.smap[nex.x][nex.y], nex.smap[now.x][now.y]);
swap(nex.smap[nowPeo.x][nowPeo.y], nex.smap[startPeo.x][startPeo.y]);
visBox[nex.x][nex.y][i] = true;
if (mp[nex.x][nex.y] == 3) //箱子到达终点
return nex.step;
q.push(nex);
}
}
}
}
return -1;
}
int main()
{
int T;
cin >> T;
while (T--)
{
cin >> M >> N;
for (int i = 0; i < M; i++) //输入地图
{
for (int j = 0; j < N; j++)
{
cin >> mp[i][j];
//在每个状态中存储地图,为了在搜索过程中,更新地图状态时,不破坏原地图
startBox.smap[i][j] = mp[i][j];
if (mp[i][j] == 2) //箱子起点
{
startBox.x = i;
startBox.y = j;
startBox.step = 0;
}
}
}
cout << bfs_box() << endl;
}
return 0;
}
继续加油。