2017-03-11 贪吃蛇

来源:互联网 发布:域名系统dns的作用 编辑:程序博客网 时间:2024/05/04 19:38

Description

身长为L的贪吃蛇在一个有障碍的N*M的格子中游走,问最少用多少步才能让贪吃蛇的蛇头到达(1,1)。

Input

第一行三个正整数 N, M,L。L表示贪吃蛇的长度。
接下来 L 行,顺序描述贪吃蛇每节身体的位置。每行两个正整数 X,Y。 表示某节身体的位置,按蛇头到蛇尾的顺序描述。
接下来一个正整数K。 表示有 K个障碍,每个障碍占一个格子。
接下来K行, 每行两个正整数 X,Y, 表示某个障碍的位置。

Output

一个整数,表示到达格子(1,1)最少的步数。(给定数据保证能够到达,并且蛇头移动的目标格子必须是空的。)

Sample Input

5 6 4
4 1
4 2
3 2
3 1
3
2 3
3 3
3 4

Sample Output

9

Hint

对于 100% 的数据,2≤N、M≤20,2≤L≤8

Source

搜索,A*搜索,状态压缩

Solution

直接BFS,不过这里的vis状态表示要注意。由于蛇最长为8格。所以我们用vis[21][21][1<<14] 表示蛇的这种状态是否已经出现.其中vis的前两维表示蛇头的坐标,后一维的二进制形式的每2位(可表0-3)表示从1到L-1开始该蛇的身体在该蛇身体的前一格的方向(后一格相对于前一格的方向).这样我们就能用最小的空间表示完整个蛇在迷宫的状态了.
现在要求最小距离,我们不用dist[][][]了,因为太耗空间了.我们用Node节点,Node中有x,y,st,dist 4个属性,前3个属性对应vis数组的前三维.最后一个属性是当前状态的最小距离.
在BFS扩展的时候,对于4个方向,计算得到nx和ny,然后判断nx和ny是否越界,是否是障碍,是否会与蛇的旧身体位置冲突.如果以上情况都不会发生,那么就生成了一个蛇与迷宫的新状态.
注意这里记录的st状态中的方向是指,后面一个格子(蛇的身体)处于前面一个格子(蛇的身体)的哪个方向.所以在BFS的时候,那个d要取反方向才能加到新的nst中.具体实现见代码.
思路2:对蛇身进行哈希判重,同样也要注意,下一步不能是前一个状态蛇身上的节点。http://www.cnblogs.com/yongze103/archive/2010/10/05/1843538.html

Code

#include<cstdio>  #include<cstring>  #include<algorithm>  #include<queue>  using namespace std;  const int maxr=21;  const int maxc=21;  int vis[maxr][maxc][1<<14];//vis第三维的高位二进制表示紧接着蛇头的那格在蛇头的相对方向  int maze[maxr][maxc];  int R,C;  struct Node//注意这里记录的st状态中的方向是指,后面一个格子处于前面一个格子的哪个方向  {      int x,y;      int st,dist;      Node(int x,int y,int st,int dist):x(x),y(y),st(st),dist(dist){}  };  int L;//蛇长  int dir[10];//用来保存解码后的方向  int dx[]={1,0,-1,0};//下,左,上,右  int dy[]={0,-1,0,1};  bool check(int x,int y,Node node)//判断x,y坐标是否处于node状态的蛇身 , 下一步的蛇头 {      for(int i=L-1;i>=1;i--)      {          dir[i]=node.st&3;//提取相对方向          node.st>>=2;      }      int xx=node.x,yy=node.y;      for(int i=1;i<L;i++)      {          xx+= dx[dir[i]];          yy+= dy[dir[i]];          if(xx==x&&yy==y) return true;//表示冲突      }      return false;//表示无冲突  }  queue<Node> Q;  int BFS(Node nod)  {      if(nod.x==1&&nod.y==1) return 0;      while(!Q.empty())Q.pop();      Q.push(nod);      vis[nod.x][nod.y][nod.st]=1;      while(!Q.empty())      {          Node node=Q.front();Q.pop();          int x=node.x,y=node.y,st=node.st,dist=node.dist;          for(int d=0;d<4;d++)          {              int nx=x+dx[d],ny=y+dy[d];              if(nx==1&&ny==1) return dist+1;              if(nx<1||nx>R||ny<1||ny>C||maze[nx][ny]==1||check(nx,ny,node)) continue;              int ndist=dist+1,nst=(st>>2)+( ((d+2)%4)<<(2*(L-2)));//新距离,新状态,注意这里(d+2)%4表示对d取反向              if(vis[nx][ny][nst]==1)continue;//之前走过              Q.push(Node(nx,ny,nst,ndist));              vis[nx][ny][nst]=1;          }      }      return -1;  }  int main()  {      while(scanf("%d%d%d",&R,&C,&L)==3)      {          if(R==0&&C==0&&L==0) break;          int x,y,nx,ny;          Node node(0,0,0,0);          scanf("%d%d",&node.x,&node.y);          x=node.x,y=node.y;          for(int i=1;i<L;i++)          {              scanf("%d%d",&nx,&ny);              for(int d=0;d<4;d++)              {                  if(x+dx[d]==nx && y+dy[d]==ny)                  {                      node.st = (node.st<<2)+d;                      break;                  }              }              x=nx,y=ny;          }          int blocks;          scanf("%d",&blocks);          memset(maze,0,sizeof(maze));          for(int i=1;i<=blocks;i++)          {              scanf("%d%d",&x,&y);              maze[x][y]=1;          }          printf("%d\n",BFS(node));      }      return 0;  }  

其实,广搜也很OK

1 0
原创粉丝点击