正文

迷宫的算法2005-04-24 22:17:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/goal00001111/705.html

分享到:

深度搜索:
/*迷宫的算法*/
/*   先建立迷宫(外围建筑围墙),设置入口和出口。建立链表,把第一个点(入口)入舰,同时做好
标记,以免重复入舰。a:判断舰顶元素的东面是否可通,若可通则将其入舰 ,同时做好标记,
以免重复入舰;若不通则判断舰顶元素的南面是否可通,依此操作至北面元素。
    判断新的舰顶元素是否为出口 ,若是,则报告结束,并打印出路径;否则递归操作a:。
    若舰顶元素其余三面皆不通 ,则将舰顶元素其重新设定为不通,以免以后再走弯路。然后退舰。
    重复a;操作。
    若退回到入口,则表示迷宫走不通,报告不通。*/
/*2005-4-22 梁见斌*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define OK 1
#define NO 0
#define OVERFLOW 1
#define M 5
#define N 5


typedef struct poi{/*建立链表结构,存储每个路径点的有关数据;横坐标,纵坐标,所指方向和向下的指针*/
   int x;
   int y;
   char *p;
   struct poi *next;
} Point;
Point *head;
char a[100][200];
char FX[14]={'E','S','W','N','E','S','W', 'E','N','W','S','E','N','W',};/*存储方向*/
int MG_S[M+2][N+2], MG[M+2][N+2], In[2], Out[2], X_Y[2];/*分别存储迷宫,入,出口和当前坐标*/
int FX_Head, FX_Tail, row=0;

void Build(void);/*建立迷宫(外围建筑围墙),设置入口和出口*/
void B_IO(void);
void Copy(void);
void B_Head(int start);
void Go(void);/*主要操作,可递归调用*/
int Judge(void);/*判断下一结点是否可通,若可通则记录该点坐标,并返回可通标志*/
void Print(Point *head);/*打印行进路径*/
void Push(Point **head);/*将当前结点入舰,并做记号表示该点已经走过*/
void Pop(Point **head);/*将当前结点退舰,并做记号表示该点不通*/
void Pop_Or_No(int end);/*判断舰顶元素所指方向是否为北,若是则退舰,否则继续判断下一方向*/
void Store(Point *head);
void Pai_Xu(void);
void Xiao_Chu(void);
void Print_Total(void);
void Free(void);
void Change(Point **head);/*原链表从表头入出舰,故表头元素表示出口坐标,表尾元素表示入口坐标,
                          打印出来的路径图是反的,不合习惯,故用此函数将表头和表尾互换,其他
                          元素依次调换*/

int main(void)
{
   int flag, i, m, n;
   
a: Build();
b: for(i=0; i<4; i++)
   {
      FX_Head = i;   FX_Tail = i + 3;
      if(i == 0)
          B_IO();
      Copy();
      B_Head(FX_Head);
      Go();
   }
   for(i=7; i<11; i++)
   {
      FX_Head = i;   FX_Tail = i + 3;
      Copy();
      B_Head(FX_Head);
      Go();
   }
   Pai_Xu();
   Xiao_Chu();
   Print_Total();
   
      puts("do you want play again? 2 to change the I_O,1 to change the MG, 0 to quit: ");
      scanf("%d", &flag);
      if(flag == 1)
      {  
         Free();
         row = 0;
          goto a;
   }
      else if(flag == 2)
      {  
         Free();
         row = 0;
          goto b;
   }         
   system("pause");
   return 0;      
}

void Build(void)  /*建立迷宫(外围建筑围墙),设置入口和出口*/
{
   int i, j;
   puts("Build the MG");
   for(i=1; i<=M; i++)
       for(j=1; j<=N ; j++)
            scanf("%d", &MG_S[i][j]);   
   fflush(stdin);
   for(i=0; i<=M+1; i++) /*外围建筑围墙*/
   {
      MG_S[i][0] = 1;
      MG_S[i][N+1] = 1;
   }  
   for(j=0; j<=N+1; j++) /*外围建筑围墙*/
   {
      MG_S[0][j] = 1;
      MG_S[M+1][j] = 1;
   }      
}  

void B_IO(void)
{
    int i, j;
    for(i=0; i<=M+1; i++)/*输出迷宫图案*/
    {
      for(j=0; j<=N+1; j++)
               printf("%d  ", MG_S[i][j]);
         printf("\n");
    }
    puts("Input the In Position");        
    for(i=0; i<2; i++)
       scanf("%d", &In[i]);
       puts("Input the Out Position");
       for(i=0; i<2; i++)
       scanf("%d", &Out[i]);
}   

void Copy(void)
{
    int i, j;
    for(i=0; i<=M+1; i++) /*把原始迷宫复制到待测迷宫中*/
       for(j=0; j<=N+1; j++)
         MG[i][j] = MG_S[i][j];
}   

void B_Head(int start)
{
   
   head = (Point *)malloc(sizeof(Point));/*建立链表,把第一个点(入口)入舰*/
   if(!head)
      {
         puts("出错了!");
         getchar();
         exit(OVERFLOW);
      }
      head->x = In[0];
      head->y = In[1];
      head->p = &FX[start];
      head->next = NULL;
   MG[head->x][head->y] = -1;/*表示该点已经走过*/   
}

void Go(void)  /*主要操作,可递归调用*/
{
   int flag, i;
   
   flag = Judge(); /*判断下一结点是否可通*/
   if(flag == 3) /*判断新的舰顶元素是否为出口 ,若是,则报告结束,并打印出路径*/
   {
      Push(&head);
      puts("\nsuccess!");
      Change(&head);
      Store(head);
   }   
   else if(flag == 1)/*若可通则将其入舰 */
      {
        Push(&head);
         Go();        
   }  
   else /*若不通,则判断舰顶元素所指方向是否为北,以便决定是否退舰*/
      Pop_Or_No(FX_Tail);   
}

int Judge(void)   /*判断下一结点是否可通,若可通则记录该点坐标,并返回可通标志*/
{
   switch( *(head->p))
   {
      case 'E': /*若舰顶元素指向东,则下一结点坐标为MG[head->x][head->y + 1]*/
      {
         if(head->x == Out[0] && head->y + 1 == Out[1])
         {
            X_Y[0] = head->x;
            X_Y[1] = head->y + 1;
             return 3;  /*若下一结点可通,返回值1*/
         }  
         else if(MG[head->x][head->y + 1] == 0)
         {
            X_Y[0] = head->x;
            X_Y[1] = head->y + 1;
             return 1;  /*若下一结点可通,返回值1*/
         }      
            else
                return 0; /*若下一结点不可通,返回值0*/
      }
      case 'S':
      {
         if(head->x + 1 == Out[0] && head->y == Out[1])
         {
            X_Y[0] = head->x + 1;
            X_Y[1] = head->y;
             return 3;  /*若下一结点可通,返回值1*/
         }
         else if(MG[head->x + 1][head->y] == 0)
         {
            X_Y[0] = head->x + 1;
            X_Y[1] = head->y ;
             return 1;
         }
            else
                return 0;
      }
      case 'W':
      {
         if(head->x == Out[0] && head->y - 1 == Out[1])
         {
            X_Y[0] = head->x;
            X_Y[1] = head->y - 1;
             return 3;  /*若下一结点可通,返回值1*/
         }
         else if(MG[head->x][head->y - 1] == 0)
         {
            X_Y[0] = head->x;
            X_Y[1] = head->y - 1;
             return 1;
         }
            else
                return 0;
      }
      case 'N':
      {
          if(head->x - 1 == Out[0] && head->y == Out[1])
         {
            X_Y[0] = head->x - 1;
            X_Y[1] = head->y;
             return 3;  /*若下一结点可通,返回值1*/
         }
         else if(MG[head->x-1][head->y] == 0)
         {
            X_Y[0] = head->x - 1;
            X_Y[1] = head->y;
             return 1;
         }
            else
                return 0;
      }  
   }   
}

void Push(Point **head) /*将当前结点入舰,并做记号表示该点已经走过*/
{
   Point *r, *s;

   s = (Point *)malloc(sizeof(Point));
   if(!s)
      {
         puts("出错了!");
         getchar();
         exit(OVERFLOW);
      }
      s->x = X_Y[0];
      s->y = X_Y[1];
      s->p = &FX[FX_Head];
      MG[s->x][s->y] = -1;/*表示该点已经走过*/
      s->next = *head;;
      *head = s;
}   

void Pop_Or_No(int end) /*判断舰顶元素所指方向是否为北,若是则退舰,否则继续判断下一方向*/
{
   if(*(head->p) != FX[end])
   {
      (head->p)++;
      Go();
   }
   else
   {
      if(head->x == In[0] && head->y == In[1]) /*若退回到入口,且入口指向北,则表示迷宫走不通*/
            puts("fail!");
      else
      {
         Pop(&head);
         if(head->x == In[0] && head->y == In[1]) /*若退回到入口,且入口指向北,则表示迷宫走不通*/
            {
               if(*(head->p) != FX[end])
            {
               (head->p)++;
               Go();
            }
               else
                  puts("fail!");    
         }          
         else
             Pop_Or_No(end);
         }
   }
}  

void Pop(Point **head) /*将当前结点退舰,并做记号表示该点不通*/
{
    Point *s;
    
    s = *head;
    *head = s->next;
    MG[s->x][s->y] = 1; /*记号表示该点不通*/
    free(s);
}   

void Change(Point **head)  //原链表从表头入出舰,故表头元素表示出口坐标,表尾元素表示入口坐标,                        
{
   Point *p, *q, *r;    //打印出来的路径图是反的,不合习惯,故用此函数将表头和表尾互换,
                          //其他元素依次调换。
   p = *head;
   q = p->next;
   while(q != NULL)
   {
      r = q->next;
      q->next = p;
      p = q;
      q = r;
   }  
   (*head)->next = NULL;
   *head = p;
}

void Print(Point *head)  /*打印行进路径*/
{
   Point *r;
   
   r = head;
   while(r->next != NULL)
   {
         printf("(%d,%d)-> ", r->x, r->y);
         r = r->next;
   }      
   printf("(%d,%d)", r->x, r->y);  
}   

void Store(Point *head)
{
   int i=0, flag=1;
   char *s;
   
   while(flag)
   {
      if(head->next != NULL)
      {
         a[row][i++] = '(';
         a[row][i++]  = (char)(head->x + 48);
         a[row][i++]   = ',';
         a[row][i++]   = (char)(head->y + 48);
         a[row][i++]   = ')';
         a[row][i++]  = '-';
         a[row][i++]  = '>';
         a[row][i++] = ' ';
         head = head->next;
      }
      else
          flag = 0;   
   }   
   a[row][i++]  = '(';
   a[row][i++] = (char)(head->x + 48);
   a[row][i++]  = ',';
   a[row][i++]  = (char)(head->y + 48);
   a[row][i++]  = ')';
   a[row][i++]  = '\0';
   row++;
}  

void Pai_Xu()
{
   int i, j, min;
   char p[200];
   
   for(i=0; i<row-1; i++)
   {
      min = i;
      for(j=i+1; j<row; j++)
         if(strlen(a[min]) > strlen(a[j]) )
             min = j;
      if(min != i)
      {
         strcpy(p, a[i]);
         strcpy(a[i], a[min]);
         strcpy(a[min], p);
      }
   }          
}

void Xiao_Chu()
{
   int i, j;
   char p[200]="fail";
   
   for(i=0; i<row-1; i++)
       for(j=i+1; j<row; j++)
            if(strcmp(a[i], a[j]) == 0)    
             strcpy(a[j], p);
}  

void Print_Total()
{
   int i;
   
   puts("\nthe total root:");
   for(i=0; i<row-1; i++)
       if(strcmp(a[i], "fail") != 0)    
          puts(a[i]);
}

void Free(void)
{
   Point *r;
   
   while(head)
   {
      r = head;
      head = head->next;
      free(r);
   }   
}  
              

广度搜索;
/*可以玩多次*/
/*迷宫的算法*/
/*   先建立迷宫(外围建筑围墙),设置入口和出口。建立链表队列,把第一个点(入口)入队,同时做好
标记,以免重复入队。
依次判断队头元素的东,南,西,北面是否为出口 ,若是则打印路径,并发出成功信号;
否则判断队头元素的该方向是否可通,若可通则将其入队 ,同时做好标记,
以免重复入队;
若未收到成功信号,则表示迷宫走不通,报告不通。*/
/*2005-4-22 梁见斌*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define OK 1
#define NO 0
#define OVERFLOW 1
#define M 5
#define N 5

typedef struct poi{/*建立链表结构,存储每个路径点的有关数据;横坐标,纵坐标,向上的指针和向下的指针*/
   int x, y;
   struct poi *pre, *next;
} Point;
Point *head, *front, *rear;
int Z_X[7]={0, 1, 0, -1, 0, 1, 0}, Z_Y[7]={1, 0, -1, 0, 1, 0, -1};/*存储方向*/
int MG_S[M+2][N+2], MG[M+2][N+2], In[2], Out[2], row=0;/*分别存储迷宫,入,出口和当前坐标*/
char a[100][200];

void Build(void);/*建立迷宫(外围建筑围墙),设置入口和出口*/
void B_IO(void);
void Copy(void);
void Go(int m, int n) ;/*主要操作*/
void Print(Point *head);/*打印行进路径*/
Point *Change(void);
void Free(void);
void Store(Point *head);
void Pai_Xu(void);
void Xiao_Chu(void);
void Print_Total(void);

int main(void)
{
   int flag, k;
   
   Build();  /*建立迷宫(外围建筑围墙),设置入口和出口*/
a: B_IO();
   k = 1;
b: Copy();
   front = (Point *)malloc(sizeof(Point));/*建立链表,把第一个点(入口)入队*/
   if(!front)
      {
         puts("出错了!");
         getchar();
         exit(OVERFLOW);
      }
      front->x = In[0];
   front->y = In[1];
   front->pre = NULL;
      front->next = NULL;
   MG[front->x][front->y] = -1;/*表示该点已经走过*/
   rear = front;
   head = front;
   if(k == 1)
   {
      k++;
         Go(0,3);  /*主要操作*/
      Free();
      goto b;
   }   
   else if(k == 2)
   {
      k++;
         Go(1,4);  /*主要操作*/
      Free();
      goto b;
   }
   else if(k == 3)
   {
      k++;
         Go(2,5);  /*主要操作*/
      Free();
      goto b;
   }
   else
          Go(3,6);  /*主要操作*/
   Pai_Xu();
   Xiao_Chu();
   Print_Total();
      puts("do you want play again? 1 to again, 0 to quit: ");
      scanf("%d", &flag);
      if(flag)
      {  
         Free();
         row = 0;
          goto a;
   }           
   system("pause");
   return 0;      
}

void Build(void)  /*建立迷宫(外围建筑围墙),设置入口和出口*/
{
   int i, j;
   puts("Build the MG");
   for(i=1; i<=M; i++)
       for(j=1; j<=N ; j++)
            scanf("%d", &MG_S[i][j]);   
   fflush(stdin);
   for(i=0; i<=M+1; i++) /*外围建筑围墙*/
   {
      MG_S[i][0] = 1;
      MG_S[i][N+1] = 1;
   }  
   for(j=0; j<=N+1; j++) /*外围建筑围墙*/
   {
      MG_S[0][j] = 1;
      MG_S[M+1][j] = 1;
   }      
}  
void B_IO(void)
{
    int i, j;
    for(i=0; i<=M+1; i++)/*输出迷宫图案*/
    {
      for(j=0; j<=N+1; j++)
               printf("%d  ", MG_S[i][j]);
         printf("\n");
    }
    puts("Input the In Position");        
    for(i=0; i<2; i++)
       scanf("%d", &In[i]);
       puts("Input the Out Position");
       for(i=0; i<2; i++)
       scanf("%d", &Out[i]);
}   

void Copy(void)
{
    int i, j;
    for(i=0; i<=M+1; i++) /*把原始迷宫复制到待测迷宫中*/
       for(j=0; j<=N+1; j++)
         MG[i][j] = MG_S[i][j];
}   
void Go(int m, int n)  /*主要操作,可递归调用*/
{
   Point *s, *p, *q;
   int flag=0, fx, i, j;
   
   while(front)
   {
       for(fx=m; fx<=n; fx++)
         {
            i = front->x + Z_X[fx];/*下一结点的坐标*/
            j = front->y + Z_Y[fx];
            if( i == Out[0] && j == Out[1])/*判断队头元素的该方向是否为出口 */
            {
               s = (Point *)malloc(sizeof(Point));
               if(!s)
                  {
                     puts("出错了!");
                     getchar();
                     exit(OVERFLOW);
                  }
                  s->x = i;
               s->y = j;
               s->pre = front;
                  s->next = NULL;
                  q = rear;
                  rear->next = s;
                  rear = rear->next;
                  MG[s->x][s->y] = -1;/*表示该点已经走过*/
                  flag = 1;   /*发出成功信号*/
                
               p = Change();
               Store(p);
                  rear = q;
            }  
            else if(MG[i][j] == 0)/*判断队头元素的该方向是否可通,若可通则将其入队 */
            {
                s = (Point *)malloc(sizeof(Point));
               if(!s)
                  {
                     puts("出错了!");
                     getchar();
                     exit(OVERFLOW);
                  }
                  s->x = i;
               s->y = j;
               s->pre = front;
                  s->next = NULL;
                  rear->next = s;
                  rear = rear->next;
               MG[s->x][s->y] = -1;/*表示该点已经走过*/      
            }
         }     
       front = front->next;  /*对头向下走,直到结尾*/
    }
    if(flag == 0)    /*若未收到成功信号,则表示迷宫走不通,报告不通。*/
          puts("fail!");
}   

void Print(Point *head)  /*打印行进路径*/
{
   Point *r;
   
   r = head;
   while(r->pre != NULL)
   {
         printf("(%d,%d)-> ", r->x, r->y);
         r = r->pre;
   }      
   printf("(%d,%d)\n", r->x, r->y);  
}   
      
Point *Change(void)  //原队列中队尾元素表示出口坐标,打印出来的路径图是反的,                        
{
   Point *p, *r, *s;    //故将原路径复制到新队列中,对调指针方向,以便打印顺序路径图,
                         
   p = rear;
   s = (Point *)malloc(sizeof(Point));
   if(!s)
      {
   puts("出错了!");
   getchar();
   exit(OVERFLOW);
      }
      s->x = p->x;
   s->y = p->y;
   s->pre = NULL;
      s->next = NULL;  
      
      r = s;
      p = p->pre;
   while(p)
   {                   
      s = (Point *)malloc(sizeof(Point));
      if(!s)
         {
            puts("出错了!");
            getchar();
            exit(OVERFLOW);
         }
         s->x = p->x;
      s->y = p->y;
      s->pre = r;
         s->next = NULL;
         
         r->next = s;
         r = s;
         p = p->pre;
      }

   return r;  /*返回复制的新队列,以便打印*/
}

void Free(void)
{
   Point *r;
   
   while(head)
   {
      r = head;
      head = head->next;
      free(r);
   }   
}

void Store(Point *head)
{
   int i=0, flag=1;
   
   while(flag)
   {
      if(head->pre != NULL)
      {
         a[row][i++] = '(';
         a[row][i++]  = (char)(head->x + 48);
         a[row][i++]   = ',';
         a[row][i++]   = (char)(head->y + 48);
         a[row][i++]   = ')';
         a[row][i++]  = '-';
         a[row][i++]  = '>';
         a[row][i++] = ' ';
         head = head->pre;
      }
      else
          flag = 0;   
   }   
   a[row][i++]  = '(';
   a[row][i++] = (char)(head->x + 48);
   a[row][i++]  = ',';
   a[row][i++]  = (char)(head->y + 48);
   a[row][i++]  = ')';
   a[row][i++]  = '\0';
   row++;
}  

void Pai_Xu()
{
   int i, j, min;
   char p[200];
   
   for(i=0; i<row-1; i++)
   {
      min = i;
      for(j=i+1; j<row; j++)
         if(strlen(a[min]) > strlen(a[j]) )
             min = j;
      if(min != i)
      {
         strcpy(p, a[i]);
         strcpy(a[i], a[min]);
         strcpy(a[min], p);
      }
   }          
}

void Xiao_Chu()
{
   int i, j;
   char p[200]="fail";
   
   for(i=0; i<row-1; i++)
       for(j=i+1; j<row; j++)
            if(strcmp(a[i], a[j]) == 0)    
             strcpy(a[j], p);
}  

void Print_Total()
{
   int i;
   
   puts("\nthe total root:");
   for(i=0; i<row-1; i++)
       if(strcmp(a[i], "fail") != 0)    
          puts(a[i]);
}
                 

阅读(3505) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册