HDU1254推箱子(AC)

本文介绍了一种经典的推箱子游戏的解题思路,利用BFS算法进行搜索,并结合地图边界和障碍物限制,实现了对箱子最少移动步数的有效计算。
推箱子是一个很经典的游戏.今天我们来玩一个简单版本.在一个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
#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

//AC

//BFS+BFS

//第一次提交WA,找找错在哪儿?如果箱子被推到一面墙上,那么箱子只能沿着墙移动这边,但是我已经控制住了,左右都动不了的
//问题还在于要确认人的位置能否到箱子的四周,这个也要确定的啊,第一次做没有确定

//第2次修改还是WA,已经加上对人的判断了,还是不对,网上搜了下有人说用DFS+BFS,但是自己的方法是BFS+BFS,我还是倾向于用BFS,这样代码好写些,DFS当然也是要练习的
//我把人和箱子的状态只走一遍应该是对的,是对的,但是要注意那个人的位置应该是原始箱子的位置
//自己第二次提交还是WA的原因后来走查代码看了好多遍终于发现ans没有Init,ans=-1要写,要不然后面如果有-1的根本就还是上一次的值就不对了
//AC

#define MAX 10

int M = 0;
int N = 0;
int ans = -1;

int startx = 0;
int starty = 0;
int px = 0;
int py = 0;
int endx = 0;
int endy = 0;

int map[MAX][MAX];
//int visit[MAX][MAX];

typedef struct node
{
	int px;  //人站的位置
	int py;
	int x;   //箱子站的位置
	int y;
	int step;
}nodes;

typedef struct ppp
{
	int x;   
	int y;
}ppps;

nodes que[MAX*MAX];
ppps person[MAX*MAX];

int dir[4][2] = { { -1, 0 }, { 1, 0 }, { 0, -1 }, {0,1} };
int visit[MAX][MAX][MAX][MAX];
int visitperson[MAX][MAX];

void init()
{
	int j = 0;
	int m = 0;
	int n = 0;
	int k = 0;
	int i = 0;
	for (j = 0; j < MAX; j++)
	{
		for (m = 0; m < MAX; m++)
		{
			map[j][m]   = 0; 
			que[n].px   = 0;
			que[n].py   = 0;
			que[n].x    = 0;
			que[n].y    = 0;
			que[n].step = 0;
			visitperson[j][m] = 0;
			person[n].x = 0;
			person[n].y = 0;
			n += 1;

			for (k = 0; k < MAX; k++)
			{
				for (i = 0; i < MAX; i++)
				{
					visit[j][m][k][i] = 0;
				}
			}
		}
	}
	startx = 0;
	starty = 0;
	px = 0;
	py = 0;
	endx = 0;
	endy = 0;
	ans = -1;
	return;
}

void initperson()
{
	int j = 0;
	int m = 0;
	int n = 0;
	for (j = 0; j < MAX; j++)
	{
		for (m = 0; m < MAX; m++)
		{

			visitperson[j][m] = 0;
			person[n].x = 0;
			person[n].y = 0;
			n += 1;
		}
	}
	return;
}

//人的位置能否走到
int bfsperson(int startx, int starty, int enddx, int enddy,int boxx,int boxy)
{
	initperson();
	int front = 0;
	int back = 0;
	int tmpx = 0;
	int tmpy = 0;
	int i = 0;
	person[back].x   = startx;
	person[back++].y = starty;

	visitperson[startx][starty] = 1;
	while (front<back)
	{
		if ((enddx == person[front].x) && (enddy == person[front].y))
		{
			return 1;
		}
		for (i = 0; i < 4;i++)
		{
			tmpx = person[front].x + dir[i][0];
			tmpy = person[front].y + dir[i][1];
			if (((tmpx<1) || (tmpx>M)) || ((tmpy<1) || (tmpy>N))) continue;
			if (1 == map[tmpx][tmpy]) continue; //墙不能走
			if ((tmpx == boxx) && (tmpy == boxy)) continue; //箱子不能走
			//if ((tmpx == enddx) && (tmpy == enddy)) continue; //箱子不能走
			if (1 == visitperson[tmpx][tmpy]) continue; //访问过不能走
			person[back].x   = tmpx;
			person[back++].y = tmpy;
			visitperson[tmpx][tmpy] = 1;
		}
		front += 1;
	}
	return 0;
}

//箱子的位置能否走到
void bfs(int x, int y)
{
	int front = 0;
	int back    = 0;
	int i       = 0;
	int tmpx    = 0;
	int tmpy    = 0;
	int tmpboxx = 0;
	int tmpboxy = 0;

	//人和箱子一开始是不在一起的,人要先到箱子的周围吧,但是是问箱子要退多少格,那人的初始位置在哪儿貌似不重要啊
	que[back].px     = px;
	que[back].py     = py;
	que[back].x      = startx;
	que[back].y      = starty;
	que[back++].step = 0;
	//visit[px][py][startx][starty] = 1;

	while (front < back)
	{
		if ((endx == que[front].x) && (endy == que[front].y))
		{
			ans = que[front].step;
			return;
		}

		if (((1 == que[front].x) && (1 == que[front].y)) || ((1 == que[front].x) && (N == que[front].y)) || ((M == que[front].x) && (1 == que[front].y)) || ((M == que[front].x) && (N == que[front].y)))
		{
			front += 1;
			continue;
		}

		for (i = 0; i < 4;i++)
		{
			tmpx = que[front].x + dir[i][0]; //箱子周围的位置也就是人站的位置
			tmpy = que[front].y + dir[i][1];
			if (((tmpx<1) || (tmpx>M)) || ((tmpy<1) || (tmpy>N))) continue;			
			if (1 == map[tmpx][tmpy]) continue; //墙不能走
			if (0 == bfsperson(que[front].px, que[front].py, tmpx, tmpy, que[front].x, que[front].y)) continue; //人是否到达这个位置
			
			//人在箱子的下面
			if ((1 == (tmpx - que[front].x)) && (tmpy == que[front].y))
			{
				tmpboxx = que[front].x - 1;
				tmpboxy = que[front].y;
				if (((tmpboxx<1) || (tmpboxx>M)) || ((tmpboxy<1) || (tmpboxy>N))) continue;
				//if (((1 == tmpboxx) && (1 == tmpboxy)) || ((1 == tmpboxx) && (N == tmpboxy)) || ((M == tmpboxx) && (1 == tmpboxy)) || ((M == tmpboxx) && (N == tmpboxy))) continue;
				if (1 == map[tmpboxx][tmpboxy]) continue; //墙不能走

				if (1 == visit[que[front].x][que[front].y][tmpboxx][tmpboxy]) continue;

				que[back].px = que[front].x; //这是个问题,这边的位置不对,人站的地方应该是箱子在的地方了,而不是应该写成tmpx,这个就不对了que[back].px = tmpx;,不对
				que[back].py = que[front].y;
				que[back].x  = tmpboxx;
				que[back].y  = tmpboxy;
				que[back++].step = que[front].step+1;
				visit[que[front].x][que[front].y][tmpboxx][tmpboxy] = 1;
			}
			//人在箱子的上面
			if ((1 == (que[front].x - tmpx)) && (tmpy == que[front].y))
			{
				tmpboxx = que[front].x + 1;
				tmpboxy = que[front].y;
				if (((tmpboxx<1) || (tmpboxx>M)) || ((tmpboxy<1) || (tmpboxy>N))) continue;
				//if (((1 == tmpboxx) && (1 == tmpboxy)) || ((1 == tmpboxx) && (N == tmpboxy)) || ((M == tmpboxx) && (1 == tmpboxy)) || ((M == tmpboxx) && (N == tmpboxy))) continue;
				if (1 == map[tmpboxx][tmpboxy]) continue; //墙不能走

				if (1 == visit[que[front].x][que[front].y][tmpboxx][tmpboxy]) continue;

				que[back].px = que[front].x;
				que[back].py = que[front].y;
				que[back].x = tmpboxx;
				que[back].y = tmpboxy;
				que[back++].step = que[front].step + 1;
				visit[que[front].x][que[front].y][tmpboxx][tmpboxy] = 1;
			}

			//人在箱子的左边
			if ((que[front].x == tmpx) && (1 == (que[front].y - tmpy)))
			{
				tmpboxx = que[front].x ;
				tmpboxy = que[front].y +1;
				if (((tmpboxx<1) || (tmpboxx>M)) || ((tmpboxy<1) || (tmpboxy>N))) continue;
				//if (((1 == tmpboxx) && (1 == tmpboxy)) || ((1 == tmpboxx) && (N == tmpboxy)) || ((M == tmpboxx) && (1 == tmpboxy)) || ((M == tmpboxx) && (N == tmpboxy))) continue;
				if (1 == map[tmpboxx][tmpboxy]) continue; //墙不能走

				if (1 == visit[que[front].x][que[front].y][tmpboxx][tmpboxy]) continue;

				que[back].px = que[front].x;
				que[back].py = que[front].y;
				que[back].x = tmpboxx;
				que[back].y = tmpboxy;
				que[back++].step = que[front].step + 1;
				visit[que[front].x][que[front].y][tmpboxx][tmpboxy] = 1;
			}

			//人在箱子的右边
			if ((que[front].x == tmpx) && (1 == (tmpy - que[front].y)))
			{
				tmpboxx = que[front].x;
				tmpboxy = que[front].y - 1;
				if (((tmpboxx<1) || (tmpboxx>M)) || ((tmpboxy<1) ||  (tmpboxy>N)))continue;
				if (1 == map[tmpboxx][tmpboxy]) continue;
				//if (((1 == tmpboxx) && (1 == tmpboxy)) || ((1 == tmpboxx) && (N == tmpboxy)) || ((M == tmpboxx) && (1 == tmpboxy)) || ((M == tmpboxx) && (N == tmpboxy))) continue;

				if (1 == visit[que[front].x][que[front].y][tmpboxx][tmpboxy])continue;

				que[back].px = que[front].x;
				que[back].py = que[front].y;
				que[back].x = tmpboxx;
				que[back].y = tmpboxy;
				que[back++].step = que[front].step + 1;
				visit[que[front].x][que[front].y][tmpboxx][tmpboxy] = 1;
			}
		}
		front += 1;
	}
	return;
}

int main()
{
	int T = 0;
	int i = 0;
	int j = 0;
	int m = 0;
	freopen("input.txt","r",stdin);
	scanf("%d", &T);
	for (i = 0; i < T;i++)
	{
		init();
		scanf("%d %d", &M, &N);
		for (j = 1; j <= M; j++)
		{
			for (m = 1; m <= N; m++)
			{
				scanf("%d",&map[j][m]);
				if (2 == map[j][m])
				{
					startx = j;
					starty = m;
				}

				if (3 == map[j][m])
				{
					endx = j;
					endy = m;
				}

				if (4 == map[j][m])
				{
					px = j;
					py = m;
				}
			}
			//只能推,不能拉
		}

		if (((1 == startx) && (1 == starty)) || ((1 == startx) && (N == starty)) || ((M == startx) && (1 == starty)) || ((M == startx) && (N == starty)))
		{
			if ((startx != endx) || (starty != endy))
			{
				printf("-1\n");
			}
		}

		bfs(startx, starty);
		printf("%d\n",ans);
	}
	return 0;

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值