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