首页 > 代码库 > UVa 532 三维迷宫

UVa 532 三维迷宫

题意:三维迷宫,可以往前后左右上下8个方向移动。

思路:8个方向的移动对应8种三维坐标的变化。这里三维坐标还是按照高、行、列为x、y、z的顺序。和二维迷宫类似,但二维可以把行列统一为 行*长度+列,三维却不可以,只能用结构体。直接用结构体数组表示队列即可,结构体之间可以直接赋值。

Code:

//#define LOCAL
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

struct cell
{
  int gao,hang,lie;     
};

void process(struct cell st,int nl,int nr,int nc);
void print(int nl,int nr,int nc);

char maze[35][35][35];

int dx[]={0,0,0,0,1,-1};
int dy[]={-1,1,0,0,0,0};
int dz[]={0,0,-1,1,0,0};

int main()
{
  #ifdef LOCAL
    freopen("532.in","r",stdin);
    freopen("532.out","w",stdout);
  #endif
  
  int nl,nr,nc;
  while((scanf("%d%d%d",&nl,&nr,&nc)==3) && nl&&nr&&nc)
  {
    memset(maze,0,sizeof(maze));
    getchar();//不要忘了弃置最开始的换行符 
    int sl=0,sr=0,sc=0;
    for(int i=0;i<nl;++i)
    {
      for(int j=0;j<nr;++j)
      {
        for(int k=0;k<nc;++k)
        {
          char c=getchar();      
          maze[i][j][k]=c;
          if(c=='S')
          {sl=i;sr=j;sc=k;}//起点位置
        }
        getchar();//弃置每行后的换行      
      }
      getchar();//弃置每个块后的空行      
    }
    //print(nl,nr,nc);
    struct cell scl={sl,sr,sc};
    //printf("scl:%d %d %d\necl:%d %d %d\n",scl.hang,scl.lie,scl.gao);
    process(scl,nl,nr,nc);
  }
  //system("pause");
  return 0;
}

void process(struct cell st,int nl,int nr,int nc)
{
  struct cell queue[30*30*30+5];
  int dist[nl][nr][nc];
  memset(dist,0,sizeof(dist));
  //dist[st->gao][st->hang][st->lie]=-1;//用dist矩阵也来判断是否访问过,没访问过的为0,初始点到自己距离设为-1以区分 
  int vis[nl][nr][nc];
  memset(vis,0,sizeof(vis));
  vis[st.gao][st.hang][st.lie]=1;
  int front=0,rear=0;
  queue[rear++]=st;
  bool flag=false;
  int num=0;
  while(front<rear)
  {
    struct cell hd=queue[front++];
    int x=hd.gao;
    int y=hd.hang;
    int z=hd.lie;
    for(int i=0;i<6;++i)
    {
      int nx=x+dx[i];
      int ny=y+dy[i];
      int nz=z+dz[i];
      if(nx>=0 && nx<nl && ny>=0 && ny<nr && nz>=0 && nz<nc && (vis[nx][ny][nz]==0))
      {
        if(maze[nx][ny][nz]=='E')
        {
          flag=true;
          num=dist[nx][ny][nz]=dist[x][y][z]+1;
          break;       
        }
        else if(maze[nx][ny][nz]=='.')
        {
          vis[nx][ny][nz]=1;
          dist[nx][ny][nz]=dist[x][y][z]+1;
          struct cell ncl={nx,ny,nz};//额,这里初始化的顺序和结构体声明顺序没有一致,导致了错误~ 
          queue[rear++]=ncl;     
        }       
      }      
    }
    if(flag) break;               
  }
  if(flag) printf("Escaped in %d minute(s).\n",num);
  else printf("Trapped!\n");   
}

这里遇到了一系列的错误。。首先,觉得结构体赋值可能耗时,所以用了指针,结构体指针队列。但在下面else-if语句块里创建的结构体变量,取址加入队列,而这个变量是块作用域的,块结束时即销毁!!!(以前知道注意不能把指向局部变量的指针作为返回值,这里这种情况倒是没想到。。指针坑太多。。)

总结:不能在块外部使用块作用域变量的指针。RE错误。

第二,在构建新的结构体时,初始化的顺序没有和结构体中变量声明顺序一致,也是个问题。

第三,bfs注意要设置结点是否访问过。开始我用dist数组是否为0来表示,但是起点到自身的距离和未访问过的结点一样dist都是0。于是把起点到自身的dist设置为-1,这样引来更大的麻烦,因为本来dist为1的这样就变成了0。。。

所以总结一下,设置是否访问过的方法:要么直接用vis数组来标识即可,或者在结构体中设置一个位表示是否访问过,

要么用dist数组兼职的话,dist为0即未访问过,但是起点到自身也是0。这一点,不要修改起点到自身的距离值,而是加一个判断,判断各维索引表示的位置不是起点(参见上一题439的实现)。

错误的用指针的代码:

#define LOCAL
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

struct cell
{
  int gao,hang,lie;     
};

void process(const struct cell *st,int nl,int nr,int nc);
void print(int nl,int nr,int nc);

char maze[35][35][35];

int dx[]={0,0,0,0,1,-1};
int dy[]={-1,1,0,0,0,0};
int dz[]={0,0,-1,1,0,0};

int main()
{
  #ifdef LOCAL
    freopen("532.in","r",stdin);
    //freopen("532.out","w",stdout);
  #endif
  
  int nl,nr,nc;
  while((scanf("%d%d%d",&nl,&nr,&nc)==3) && nl&&nr&&nc)
  {
    memset(maze,0,sizeof(maze));
    getchar();//不要忘了弃置最开始的换行符 
    int sl=0,sr=0,sc=0;
    //int el,er,ec;
    for(int i=0;i<nl;++i)
    {
      for(int j=0;j<nr;++j)
      {
        for(int k=0;k<nc;++k)
        {
          char c=getchar();      
          maze[i][j][k]=c;
          if(c=='S')
          {sl=i;sr=j;sc=k;}//起点位置
          //else if(c=='E')
          //{el=i;er=j;ec=k;} 
        }
        getchar();//弃置每行后的换行      
      }
      getchar();//弃置每个块后的空行      
    }
    //print(nl,nr,nc);
    struct cell scl={sl,sr,sc};
    //struct cell ecl={el,er,ec};
    //printf("scl:%d %d %d\necl:%d %d %d\n",scl.hang,scl.lie,scl.gao);
    process(&scl,nl,nr,nc);
  }
  //system("pause");
  return 0;
}

void process(const struct cell *st,int nl,int nr,int nc)
{
  const struct cell *queue[30*30*30+5];
  int dist[nl][nr][nc];
  memset(dist,0,sizeof(dist));
  //dist[st->gao][st->hang][st->lie]=-1;//用dist矩阵也来判断是否访问过,没访问过的为0,初始点到自己距离设为-1以区分 
  int vis[nl][nr][nc];
  memset(vis,0,sizeof(vis));
  vis[st->gao][st->hang][st->lie]=1;
  int front=0,rear=0;
  queue[rear++]=st;
  bool flag=false;
  int num=0;
  while(front<rear)
  {
    const struct cell *hd=queue[front++];
    int x=hd->gao;
    int y=hd->hang;
    int z=hd->lie;
    for(int i=0;i<6;++i)
    {
      int nx=x+dx[i];
      int ny=y+dy[i];
      int nz=z+dz[i];
      if(nx>=0 && nx<nl && ny>=0 && ny<nr && nz>=0 && nz<nc && (vis[nx][ny][nz]==0))
      {
        if(maze[nx][ny][nz]=='E')
        {
          flag=true;
          num=dist[nx][ny][nz]=dist[x][y][z]+1;
          break;       
        }
        else if(maze[nx][ny][nz]=='.')
        {
          vis[nx][ny][nz]=1;
          dist[nx][ny][nz]=dist[x][y][z]+1;
          struct cell ncl={nx,ny,nz};//额,这里初始化的顺序和结构体声明顺序没有一致,导致了错误~ 
          queue[rear++]=&ncl;     
        }       
      }      
    }
    if(flag) break;               
  }
  if(flag) printf("Escaped in %d minute(s).\n",num);
  else printf("Trapped!\n");   
}

void print(int nl,int nr,int nc)
{
  for(int i=0;i<nl;++i)
   for(int j=0;j<nr;++j)
     maze[i][j][nc]='\0';
     
  for(int i=0;i<nl;++i)
  {
   for(int j=0;j<nr;++j)
   {
     printf("%s\n",maze[i][j]);        
   }
   printf("\n");
  }   
}


UVa 532 三维迷宫