/**************************************************************
作者:陈新
邮箱:cx2pirate@gmail.com
用途:hdu1254_2
时间ﺿ014.3.31 21:11
测试ﺿ0447364 2014-04-01 08:51:18 Accepted 1254 15MS 296K 3724 B G++ 超级旅行者
*************************************************************/
#include <cstdio>
#include <memory.h>
#include <queue>
#include <map>
using namespace std;
#define MAPSIZE 7
#define FLOOR 0
#define WALL 1
#define BOX 2
#define DESTINATION 3
#define WORKER 4
//坐标
typedef struct COOR{
int x,y;
bool operator ==(const COOR &rhs) const{
return x == rhs.x && y == rhs.y;
}
bool operator !=(const COOR &rhs) const{
return x != rhs.x || y != rhs.y;
}
bool operator <(const COOR &rhs) const{
return x < rhs.x || (x == rhs.x && y < rhs.y);
}
}COOR;
//worker,box的位置组成搜索节点
//为使用map 对运算法重载
typedef struct NODE{
COOR worker;
COOR box;
int dir;
int steps;
bool operator <(const NODE &rhs)const{
return worker < rhs.worker || (worker == rhs.worker && box < rhs.box);
}
}NODE;
int gMap[MAPSIZE][MAPSIZE]; //地图
int vis[MAPSIZE][MAPSIZE]; //dfs中使用,
int mapX,mapY; //mapX地图高,mapY地图宽
bool found;
int DIREC[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
int REVER[4] = {1,0,3,2}; //DIREC中反方向对应的索引
queue<NODE> unvis;
map<NODE,bool> visited; //用map记录已经扩展的节点,
void initMap(); //初始化地图
int findAWay(); //找到推箱子路径,有路径返回最小步骤,否则返回-1
void getCoor(COOR *worker,COOR *box,COOR *dest); //从地图中获得worker,box,destination初始坐标
COOR move(COOR from,int dir); //移动一个坐标,返回移动后的坐标
void addNodes(COOR worker,COOR box,int steps); //把worker移动到box上下左右组成搜索节点,添加到unvis
bool reach(COOR worker,COOR box,COOR aroundBox); //返回worker是否能到达box周围的坐标aroundBox
void dfs(COOR worker,COOR box,COOR aroundBox); //reach中采用的dfs
bool notWall(COOR pos); //坐标在地图内且不是墙返回真,否则返回假
int main(){
int caseNum;
scanf("%d",&caseNum);
while(caseNum--){
initMap();
int steps = findAWay();
printf("%d\n",steps);
}
}
void initMap(){
scanf("%d%d",&mapX,&mapY);
for(int i = 0;i < mapX;i++){
for(int j = 0;j < mapY;j++){
scanf("%d",&gMap[i][j]);
}
}
}
int findAWay(){
COOR worker,box,dest;
getCoor(&worker,&box,&dest);
visited.clear();
while(!unvis.empty()){
unvis.pop();
}
addNodes(worker,box,0);
while(!unvis.empty()){
NODE cur = unvis.front();
unvis.pop();
if(cur.box == dest){
return cur.steps;
}
// printf("worker : %d %d\tbox : %d %d\tsteps : %d\n",cur.worker.x,cur.worker.y,cur.box.x,cur.box.y,cur.steps);
COOR bNext = move(cur.box,cur.dir);
if(notWall(bNext)){
addNodes(cur.worker,bNext,cur.steps + 1);
}
}
return -1;
}
void addNodes(COOR worker,COOR box,int steps){
for(int dir = 0;dir < 4;dir++){
COOR aroundBox = move(box,dir);
if(reach(worker,box,aroundBox)){
NODE node;
node.worker = aroundBox;
node.box = box;
node.steps = steps;
node.dir = REVER[dir];
if(!visited[node]){
visited[node] = true;
unvis.push(node);
}
}
}
}
COOR move(COOR from,int dir){
COOR dest = from;
dest.x += DIREC[dir][0];
dest.y += DIREC[dir][1];
return dest;
}
bool reach(COOR worker,COOR box,COOR aroundBox){
memset(vis,false,sizeof(vis));
found = false;
dfs(worker,box,aroundBox);
return found;
}
void dfs(COOR worker,COOR box,COOR aroundBox){
if(worker == aroundBox){
found = true;
}
if(found){
return;
}
for(int dir = 0;dir < 4;dir++){
COOR wNext = move(worker,dir);
if(notWall(wNext) && wNext != box && !vis[wNext.x][wNext.y]){
vis[wNext.x][wNext.y] = true;
dfs(wNext,box,aroundBox);
}
}
}
bool notWall(COOR pos){
return pos.x >= 0 && pos.x < mapX && pos.y >= 0 && pos.y < mapY && gMap[pos.x][pos.y] != WALL;
}
void getCoor(COOR *worker,COOR *box,COOR *dest){
for(int i = 0;i < mapX;i++){
for(int j = 0;j < mapY;j++){
if(gMap[i][j] == WORKER){
worker ->x = i;
worker ->y = j;
}
else if(gMap[i][j] == BOX){
box ->x = i;
box ->y = j;
}
else if(gMap[i][j] == DESTINATION){
dest ->x = i;
dest ->y = j;
}
}
}
}