正文

迷宫的算法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]); }                  

阅读(3644) | 评论(0)


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

评论

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