题意:有一个(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;
}