POJ-1324-Holedox Moving

本文详细介绍了使用BFS算法解决迷宫问题的策略,特别关注如何通过状态压缩技术来高效处理蛇的身体位置。讨论了如何仅通过蛇头的位置推断整条蛇的位置,并在代码实现中展示了时间复杂度大约为1100ms的解决方案。文章还提及了对代码的不断优化和改进的可能性。

这个题好像算比较麻烦的一道BFS题,做了2个小时的样子,主要还是需要状态压缩。特别是对蛇身体的位置进行压缩,注意位运算的存入和取出的操作,因为存整个蛇身的位置是不现实的,只能存蛇身块之间的相对位置,这样的话只要知道蛇头,那么整条蛇都能够找到。

网上看到好多人对这个题进行一次又一次的改进,只能以后看时间了~这份代码时间在1100ms左右,算一般吧,因为我还不会A*算法

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=22;
struct node
{
    int x;
    int y;
    int pos;
    int ans;
}q[700000];
int n,m,l,k;
char map[maxn][maxn];
bool vis[maxn][maxn][16400];
int sx[11],sy[11],movex[4]={-1,0,1,0},movey[4]={0,1,0,-1};
bool eat(int x,int y)
{
    for(int i=0;i<l;i++)
	if(sx[i]==x&&sy[i]==y)
	    return true;
    return false;
}
int main()
{
    int cas=1;
    while(scanf("%d%d%d",&n,&m,&l)&&(n+m+l))
    {
	memset(vis,0,sizeof(vis));
	memset(map,0,sizeof(map));
	for(int i=0;i<=n+1;i++)
	    map[i][0]=map[i][m+1]='#';
	for(int i=0;i<=m+1;i++)
	    map[0][i]=map[n+1][i]='#';
	for(int i=0;i<l;i++)
	    scanf("%d%d",&sx[i],&sy[i]);
	scanf("%d",&k);
	for(int i=0;i<k;i++)
	{
	    int ita,itb;
	    scanf("%d%d",&ita,&itb);
	    map[ita][itb]='#';
	}
	int res=1,ita=0;
	for(int i=1;i<l;i++)
	{
	    if(sx[i]+1==sx[i-1])
		ita=0;
	    else if(sy[i]-1==sy[i-1])
		ita=1;
	    else if(sx[i]-1==sx[i-1])
		ita=2;
	    else
		ita=3;
	    res=(res<<2)+ita;
	}
	int pre=0,last=1;
	q[0].x=sx[0];
	q[0].y=sy[0];
	q[0].pos=res;
	q[0].ans=0;
	vis[sx[0]][sy[0]][res]=1;
	int ans=-1;
	while(pre<last)
	{
	    int x=q[pre].x;
	    int y=q[pre].y;
	    int pos=q[pre].pos;
	    if(x==1&&y==1)
	    {
		ans=q[pre].ans;
		break;
	    }
	    sx[0]=x;
	    sy[0]=y;
	    ita=pos;
	    for(int i=1;i<l;i++)
	    {
		int index=(l-i-1)*2;
		if((ita&(1<<index))&&(ita&(1<<(index+1))))
		{
		    sx[i]=sx[i-1]+movex[3];
		    sy[i]=sy[i-1]+movey[3];
		}
		else if((ita&(1<<index))&&!(ita&(1<<(index+1))))
		{
		    sx[i]=sx[i-1]+movex[1];
		    sy[i]=sy[i-1]+movey[1];
		}
		else if(!(ita&(1<<index))&&(ita&(1<<(index+1))))
		{
		    sx[i]=sx[i-1]+movex[2];
		    sy[i]=sy[i-1]+movey[2];
		}
		else
		{
		    sx[i]=sx[i-1]+movex[0];
		    sy[i]=sy[i-1]+movey[0];
		}
	    }
	    ita>>=2;
	    int index=(l-2)*2;
	    ita|=(1<<(index+2));
	    for(int i=0;i<4;i++)
	    {
		int itx=x+movex[i];
		int ity=y+movey[i];
		if(map[itx][ity]=='#')
		    continue;
		if(i==0)
		{
		    ita&=~(1<<index);
		    ita|=(1<<(index+1));
		}
		else if(i==1)
		{
		    ita|=(1<<index);
		    ita|=(1<<(index+1));
		}
		else if(i==2)
		{
		    ita&=~(1<<index);
		    ita&=~(1<<(index+1));
		}
		else
		{
		    ita|=(1<<index);
		    ita&=~(1<<(index+1));
		}
		if(vis[itx][ity][ita]||eat(itx,ity))
		    continue;
		vis[itx][ity][ita]=1;
		q[last].x=itx;
		q[last].y=ity;
		q[last].ans=q[pre].ans+1;
		q[last++].pos=ita;
	    }
	    pre++;
	}
	printf("Case %d: %d\n",cas++,ans);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值