hdoj--1254--推箱子(bfs好题)



推箱子

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 6758    Accepted Submission(s): 1906


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

感觉还是有难度的,刚开始的时候没考虑人所在的位置,这里有一个坑,箱子移动的时候人必须在箱子后边,这样才可以推到箱子,这样的话就会有点复杂,每次推箱子的时候我们都应该判断一下,上一次人所在的位置是否可以到达这次推箱子的位置,所以这就不只是一个bfs可以搞定的了,在结构体中我们记录的应该有箱子和人的位置以及当前步数,每一次位置变换都应该更新人还有箱子的位置,同时判定该方案的可行性(加上了注释就CE了,不知道是什么鬼)
#include<stdio.h>
#include<cstring>
#include<queue>
#include<iostream>
#include<algorithm>
using namespace std;
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
int map[10][10],mark[10][10][10][10];
int n,m,flag,markk[10][10];
int xiangx,xiangy;
struct dian
{
   int x,y;
   int renx,reny;
   int step;    
}st,end;
struct ren
{
   int x,y;	
}vv,stt;
int bffs(ren stt)
{
	queue<ren>q;
	markk[stt.x][stt.y]=1;
	q.push(stt);
	ren v,vn;
	while(!q.empty())
	{
		vn=q.front();
		q.pop();
		if(vn.x==vv.x&&vn.y==vv.y)  
		return 1;//可以到达现在推箱子的位置 	
		for(int i=0;i<4;i++)
		{
			v.x=vn.x+dx[i];
			v.y=vn.y+dy[i];
			if(v.x>=n||v.x<0||v.y>=m||v.y<0) 
			continue;//不能出界 
			if(map[v.x][v.y]==1)	continue;
			if(v.x==xiangx&&v.y==xiangy)  continue;
			//不能在以前箱子所在的位置 
			if(markk[v.x][v.y])  continue;
			markk[v.x][v.y]=1;
			q.push(v);
		}
	}	
	return 0;
}
void bfs(dian st)
{
	queue<dian>p;
	p.push(st);//使用人还有箱子的位置实现四维标记 
	mark[st.x][st.y][st.renx][st.reny]=1;    
	dian v,vn;
	while(!p.empty())
	{   
		vn=p.front();
		p.pop();
		if(vn.x==end.x&&vn.y==end.y)
		{//如果现在箱子被推到了指定的位置 
			flag=1;
			printf("%d
",vn.step);
			return;
		}    
		for(int i=0;i<4;i++)
		{//箱子位置变更 
			v.x=vn.x+dx[i];
			v.y=vn.y+dy[i];
			v.step=vn.step+1;
			v.renx=vn.x;
			v.reny=vn.y;
			vv.x=vn.x-dx[i];//vv中的x,y存储了推箱子时人应该在的位置 
			vv.y=vn.y-dy[i];
			if(v.x>=n||v.x<0||v.y>=m||v.y<0)  continue; 
			if(map[v.x][v.y]==1)  continue;
			if(map[vv.x][vv.y]==1||vv.x>=n||vv.x<0||vv.y>=m||vv.y<0)  continue;
			if(mark[v.x][v.y][v.renx][v.reny])  continue;
			stt.x=vn.renx;//结构体中存放的有当时人的位置 
			stt.y=vn.reny;
			xiangx=vn.x;
			xiangy=vn.y;
			memset(markk,0,sizeof(markk));
			if(!bffs(stt))  continue;//箱子被推之前的位置,因为还要判定是否可以推 
			mark[v.x][v.y][v.renx][v.reny]=1;
			p.push(v);
		}
	}
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		flag=0;
		scanf("%d%d",&n,&m);
		for(int i=0;i<n;i++)
		for(int j=0;j<m;j++)
		{
			scanf("%d",&map[i][j]);
			if(map[i][j]==2)
			{
				st.x=i;
				st.y=j;
				xiangx=i;
				xiangy=j;
			}
			if(map[i][j]==3)
			{
				end.x=i;
				end.y=j;
			}
			if(map[i][j]==4)
			{
				st.renx=i;
				st.reny=j;	
			}
		}
		st.step=0;
		memset(mark,0,sizeof(mark));
		memset(markk,0,sizeof(markk));
		bfs(st);    
		if(!flag)  printf("-1
");    
	}    
	return 0;
}

原文地址:https://www.cnblogs.com/playboy307/p/5273378.html