poj 1324 bfs(一条蛇要出洞)

题意:有一个(n*m)矩形区域,有一条蛇,蛇的最大长度为8,蛇的每一节位于一个坐标上。蛇每次可以向4邻域移动一个距离,而且规定,蛇不能触碰石头(输入给出,位置固定);蛇头不能触碰身体坐标(尾巴也不能碰)。出口坐标为(1,1),问蛇最少走多少步能够出来,不能出来则输出-1。

思路:显然是搜索。关键是如何存放状态来判重。用三维数组flag[x][y][state]来存放状态,(x,y)为坐标,state为蛇头在(x,y)的某种状态。因为有四个方向,用两位表示这四个方向,以此刻画蛇的后一节身体与前一节的关系(这也就是最大蛇长为8的提示,表示某个坐标的状态最多有1<<(2*(8-1))即2^14个,int可以存)。具体见代码注释。

#include <stdio.h>
#include <string.h>
#define N 21
typedef struct node{
	int state,x,y,step;//state是状态,step表示移动的步数
}snake;
snake q[N*N*(1<<14)];//队列
int ori[4][2]={{1,0},{0,-1},{-1,0},{0,1}};
int s[N][N],flag[N][N][1<<14];//s存放石头,flag用来判重
int n,m,len,c=1;
int valid(int x,int y,int a,int b,int state){
	int i,mask = 3,aa,bb;
	if(x<0||y<0||x>=n||y>=m)//边界外
		return 0;
	if(s[x][y])
		return 0;//遇到石头
	for(i = 0;i<len-1;i++){//遇到自己身体
		aa = a + ori[(((mask&state)>>(i<<1))+2)%4][0];//找到蛇的每节身体坐标,和新蛇头进行比较
		bb = b + ori[(((mask&state)>>(i<<1))+2)%4][1];
		if(x == aa && y == bb)
			return 0;
		a = aa;
		b = bb;
		mask <<= 2;
	}
	return 1;
}
int bfs(){
	int front,rear,i,mask = (1<<((len-1)<<1))-1;
	front = -1;
	rear = 0;
	while(front < rear){
		int xx,yy,state;
		snake now = q[++front];//队头
		for(i = 0;i<4;i++){
			xx = now.x + ori[i][0];
			yy = now.y + ori[i][1];
			state = now.state;
			state <<= 2;//表示蛇的身体向前移动一个距离
			state |= i;//表示新蛇头与原蛇头的位置关系
			state &= mask;//将原蛇尾切掉
			if(valid(xx,yy,now.x,now.y,now.state) && !flag[xx][yy][state]){//如果新位置合法而且新状态没有到达过
			 	if(!xx && !yy)//找到
					return now.step + 1;
				flag[xx][yy][state] = 1;
				q[++rear].x = xx;
				q[rear].y = yy;
				q[rear].state = state;
				q[rear].step = now.step + 1 ;
			}
		}
	}
	return 0;
}
int main(){
	freopen("a.txt","r",stdin);
	while(scanf("%d %d %d",&n,&m,&len) && (n+m+len)){
		int i,j,a,b,state=0;
		memset(flag,0,sizeof(flag));
		printf("Case %d: ",c++);
		scanf("%d %d",&s[0][0],&s[0][1]);
		q[0].x = s[0][0]-1;
		q[0].y = s[0][1]-1;
		q[0].step = 0;
		for(i = 0;i<len-1;i++){//求出蛇的初始状态
			scanf("%d %d",&s[1][0],&s[1][1]);
			if(s[1][0]==s[0][0]){
				if(s[1][1]>s[0][1])//right
					state |= (1<<(i<<1));
				else				//left
					state |= (3<<(i<<1));
			}else if(s[1][0] > s[0][0])//down
					state |= (2<<(i<<1));
			s[0][0] = s[1][0];
			s[0][1] = s[1][1];
		}
		q[0].state = state;
		flag[q[0].x][q[0].y][state] = 1;
		memset(s,0,sizeof(s));
		scanf("%d",&j);
		for(i = 0;i<j;i++){//填充石头数组
			scanf("%d %d",&a,&b);
			s[a-1][b-1] = 1;
		}
		if(!q[0].x && !q[0].y){//如果蛇头初始就在洞口
			printf("0\n");
			continue;
		}
		if(i = bfs())
			printf("%d\n",i);
		else
			printf("-1\n");
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值