HDU 1254 推箱子

题目链接:点击打开链接

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

(搬运工只能推箱子而不能拉箱子,因此如果箱子被推到一个角上(如图)那么箱子就不能再被移动了,如果箱子被推到一面墙上,那么箱子只能沿着墙移动。)



思路:很简单的状态搜索题,大概就是对箱子采用BFS的思想,然后判断人是否可以走到箱子的对面(DFS/BFS),由于数据大,可以用四重标记数组来标记(Hash[M][M][M][M])不过有许多细节需要注意。


(1)采用DFS/BFS判断人是否可以到达箱子的对面时,要明确人不能穿过箱子,即对箱子标记flag[p.Bx][p.By] = 1;而且这个判断是每次推动箱子之前都要判断的。

(2)求箱子的移动后的位置的坐标时要保证这个坐标没有超边界。

(3)DFS时不需要回溯。(设置标记数组,查找到即标记,不再查找,因为也不必要。)

(4)经测试,推箱子时,人的位置随箱子的移动而移动可以AC,人不移动(即人仍然在箱子上一步所在的位置)也可以AC。


代码如下:

#include<string>
#include<string.h>
#include<cstring>
#include<stack>
#include<queue>
#include<algorithm>
#include<math.h>
#include<vector>
#include<iomanip>
#include<map>
#include<iostream>
using namespace std;

const int M=8;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
int maze[M][M];
int n,m;
int Nx,Ny;
int Bx,By,Mx,My;
int flag[M][M],Hash[M][M][M][M];
int Found;

struct node
{
	int Bx,By;
	int Mx,My;
	int step;
};

int check(int x,int y)
{ //判断越界及墙壁
	if(x>=0&&y>=0&&y<m&&x<n&&maze[x][y]!=1)
		return 1;
	return 0;
}

void dfs(int Nx,int Ny,int Mx,int My)
{//搜索人是否能到达挨着箱子并且与箱子运动相反方向的坐标上
	if(Nx==Mx&&Ny==My)
	{
		Found=1;
		return;
	}
	for(int i=0;i<4&&!Found;i++)
	{
		int x=Nx+dx[i];
		int y=Ny+dy[i];
		if(check(x,y)&&!flag[x][y])
		{
			flag[x][y]=1;
			dfs(x,y,Mx,My);
		}
	}
}

void  bfs(int Bx,int By,int Mx,int My)
{ //搜索箱子
	queue<node>Q;
	node p,q;
	p.Bx=Bx;p.By=By;p.Mx=Mx;p.My=My;p.step=0;
	Q.push(p);
	while(!Q.empty())
	{
		p=Q.front();Q.pop();
		if(maze[p.Bx][p.By]==3)
		{
			printf("%d\n",p.step);
			return;
		}
		for(int i=0;i<4;i++)
		{
			q=p;
			q.Bx+=dx[i];
			q.By+=dy[i];
			Nx=p.Bx-dx[i];
			Ny=p.By-dy[i];
			if(check(q.Bx,q.By)&&check(Nx,Ny)&&!Hash[q.Bx][q.By][Nx][Ny])
			{
				memset(flag,0,sizeof(flag));
				flag[p.Bx][p.By]=flag[Nx][Ny]=1;
				Found=0;
				dfs(Nx,Ny,p.Mx,p.My);
				if(Found)
				{
					Hash[q.Bx][q.By][Nx][Ny]=1;
					q.Mx=p.Bx;q.My=p.By; //这里也可以写成q.Mx=Nx;q.My=Ny;
					q.step++;
					Q.push(q);
				}
			}
		}
	}
	printf("-1\n");
	return;
}

void init()
{
	memset(Hash,0,sizeof(Hash));
	memset(maze,0,sizeof(maze));
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<m;j++)
		{
			scanf("%d",&maze[i][j]);
			if(maze[i][j]==2)
			{
				Bx=i;
				By=j;
			}
			if(maze[i][j]==4)
			{
				Mx=i;
				My=j;
			}
		}
	}
}

int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&m);
		init();
		bfs(Bx,By,Mx,My);
	}
	return 0;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值