POJ-2946-The Warehouse

378 篇文章 0 订阅

唉,终于做到书中图遍历系列的最后一个题了。

题目的大意是说,你所处的一个迷宫,你只能走在有数字的方格(坐标)上,方格按照题目的意思是箱子,其为长方体(1*1*h),h即为其上面的数字。当然这里给你2种操作(方向都只有上下左右):

1、走到旁边的数字方格上面去。

2、推到你现在所站的方格,其向前倒下高度变为1.,当然前提是前面有足够多的'.'(出口E不能算作'.')即不能将箱子推到到E上面去。题目所要求箱子只能被推到一次,即在做的过程中只能推到数字大于1的,等于1的就只能行走。

注意:非数字的坐标是不能走的,要求就是求起点到终点的最小步数。

这个题明显是个BFS搜索题,关键的问题是它需要记录的状态并不像以往那样只记录坐标即可,它需要把整个图的状态也要记录下来。这就给去重复工作增添了麻烦,这里按书上的建议我采用的也是哈希表,通过一个表达式进行计算,然后得到一个状态值,判断这个状态值是否出现从而得到当前状态是否与之前的重复。这个表达式有点侥幸的感觉~

做后觉得这个题就是我们以前一个游戏的模型,还觉得比较有意思。

代码:

#include<cstdio>
#include<cstring>
#define MAX 10
#define mod 3000007
struct map
{
    char smap[MAX][MAX];
    int x,y,moves;
}q[1000000];
int n,movex[4]={1,-1,0,0},movey[4]={0,0,-1,1};
bool ipos[mod];
bool isborder(int x,int y)
{
    if(x<0||x>=n||y<0||y>=n)
	return true;
    return false;
}
int GetHash(int index)
{
    int ans=0;
    for(int i=0;i<n;i++)
	for(int j=0;j<n;j++)
	    ans=(ans*131+q[index].smap[i][j])%mod;
    ans=(ans+q[index].x*33+q[index].y*131)%mod;
    return ans;
}
int main()
{
    while(scanf("%d%d%d",&n,&q[0].x,&q[0].y)&&n)
    {
	memset(ipos,0,sizeof(ipos));
	int front=0,last=1,pos=0;
	q[0].x--;
	q[0].y--;
	q[0].moves=0;
	for(int i=0;i<n;i++)
	{
	    getchar();
	    for(int j=0;j<n;j++)
		scanf("%c",&q[0].smap[i][j]);
	}
	ipos[GetHash(0)]=1;
	int flag=0,ans=0;
	while(front!=last)
	{
	    char smap[8][8];
	    for(int i=0;i<n;i++)
		for(int j=0;j<n;j++)
		    smap[i][j]=q[front].smap[i][j];
	    int itx=q[front].x;
	    int ity=q[front].y;
	    int moves=q[front++].moves;
	    for(int i=0;i<4;i++)
	    {
		int xx=itx+movex[i];
		int yy=ity+movey[i];
		if(!(isborder(xx,yy)||smap[xx][yy]=='.'))
		{
		    if(smap[xx][yy]=='E')
		    {
			flag=1;
			ans=moves+1;
			break;
		    }
		    int hash=0;
		    for(int j=0;j<n;j++)
			for(int k=0;k<n;k++)
			    hash=(hash*131+smap[j][k])%mod;
		    if(!ipos[(hash+xx*33+yy*131)%mod])
		    {
			for(int j=0;j<n;j++)
			    for(int k=0;k<n;k++)
				q[last].smap[j][k]=smap[j][k];
			q[last].x=xx;q[last].y=yy;
			q[last].moves=moves+1;
			last++;
			ipos[(hash+xx*33+yy*131)%mod]=1;
		    }
		}
		if(smap[itx][ity]!='.'&&smap[itx][ity]!='1')
		{
		    int flaga=0,mx=itx,my=ity;
			for(int j=0;j<smap[itx][ity]-'0';j++)
			{
			    mx+=movex[i];
			    my+=movey[i];
			    if(isborder(mx,my)||smap[mx][my]!='.')
			    {
				flaga=1;
				break;
			    }
			}
			if(!flaga)
			{
			    for(int j=0;j<n;j++)
				for(int k=0;k<n;k++)
				    q[last].smap[j][k]=smap[j][k];
			    mx=itx,my=ity;
			    for(int j=0;j<smap[itx][ity]-'0';j++)
			    {
				mx+=movex[i];
				my+=movey[i];
				q[last].smap[mx][my]='1';
			    }
			    q[last].smap[itx][ity]='.';
			    q[last].x=xx;
			    q[last].y=yy;
			    q[last].moves=moves+1;
			    ipos[GetHash(last)]=1;
			    last++;
			}

		}
	    }
	    if(flag)
		break;
	}
	if(flag)
	    printf("%d\n",ans);
	else
	    printf("Impossible.\n");
    }
    return 0;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值