YbtOJ 广度搜索课堂过关 例3 立体推箱子【bfs】

102 篇文章 2 订阅
21 篇文章 0 订阅

在这里插入图片描述


思路

首先这个是广搜。
可以预处理出刚开始的箱子状态和终点。
那么 1 × 2 1\times 2 1×2 的情况怎么记录呢?
我们可以记录第一个格子,然后直接把第二个格子判断状态即可。
然后对于箱子的移动很麻烦,我们要用 d x , d y , d t dx,dy,dt dx,dy,dt 分别表示每种情况下的移动方式。
最后直接搜就好了。

C o d e Code Code

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
const int dx[4][5]={{},{0,0,1,0,-2},{0,0,1,0,-1},{0,0,2,0,-1}};
const int dy[4][5]={{},{0,1,0,-2,0},{0,2,0,-1,0},{0,1,0,-1,0}};
const int dt[4][5]={{},{0,2,3,2,3},{0,1,2,1,2},{0,3,1,3,1}};
int v[510][510][4];
char a[510][510],c;
int n,m,tx,ty;
struct node
{
	int x,y,t,c;
}f[10001000];
bool check(int x,int y,int t)
{
	if(x<1||x>n||y<1||y>m||v[x][y][t]==1)
	  return 0;
	if(t==1)
	 {
	 	if(a[x][y]=='E'||a[x][y]=='#')
	 	  return 0;
	 }
	if(t==3)
	 {
	 	if(a[x][y]=='#'||x+1>n||a[x+1][y]=='#')
	 	  return 0;
	 }
	if(t==2)
	 {
	 	if(a[x][y]=='#'||y+1>m||a[x][y+1]=='#')
	 	  return 0;
	 }
	return 1;
}
void bfs()
{
	int hd=0,tl=1;
	while(hd<tl)
	 {
	 	hd++;
	 	for(int i=1; i<=4; i++)
	 	 {
	 	 	int xx=f[hd].x+dx[f[hd].t][i];
	 	 	int yy=f[hd].y+dy[f[hd].t][i];
	 	 	int tt=dt[f[hd].t][i];
	 	 	if(check(xx,yy,tt))
	 	 	 {
	 	 	 	tl++;
	 	 	 	f[tl]=(node){xx,yy,tt,f[hd].c+1};
	 	 	 	if(xx==tx&&yy==ty&&tt==1)
	 	 	 	 {
	 	 	 	 	cout<<f[tl].c<<endl;
	 	 	 	 	return;
				 }
				v[xx][yy][tt]=1;
			 }
		 }
	 }
	cout<<"Impossible"<<endl;
}
void ycl()
{
	int w=0;
	for(int i=1; i<=n; i++)
	 for(int j=1; j<=m; j++)
	  {
	  	if(a[i][j]=='X'&&w==0)
	  	 {
	  	 	w=1;
	  	 	if(a[i][j+1]=='X')
	  	 	  f[1].x=i,f[1].y=j,f[1].t=2;
	  	 	else if(a[i+1][j]=='X')
	  	 	  f[1].x=i,f[1].y=j,f[1].t=3;
	  	 	else
	  	 	  f[1].x=i,f[1].y=j,f[1].t=1;
	  	 	v[i][j][f[1].t]=1;
		 }
		if(a[i][j]=='O')
		  tx=i,ty=j;
	  }
}
int main()
{
	while(cin>>n>>m)
	 {
	   memset(v,0,sizeof(v));
	   if(n==0&&m==0)
	     break;
	   for(int i=1; i<=n; i++)
	    for(int j=1; j<=m; j++)
	     {
	  	    a[i][j]=getchar();
	  	    while(a[i][j]!='#'&&a[i][j]!='X'&&a[i][j]!='.'&&a[i][j]!='O'&&a[i][j]!='E')
	  	      a[i][j]=getchar();
	     }
	   ycl();
	   bfs();
	 }
	return 0;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值