[ C语言 ] 迷宫 迷宫生成器 [ 递归与搜索 ]

【原创】转载请注明出处 【浙江大学 程序设计专题】

【地图求解器】

本题目要求输入一个迷宫地图,输出从起点到终点的路线。

基本思路是从起点(Sx,Sy)每次枚举该格子上下左右四个方向,直到走到终点(Tx,Ty)。
方法一:如果使用递归方法,则可以使用深度优先搜索算法,但此方法不能保证答案步数最优。
方法二: 如果要求答案步数最少,则使用广度优先搜索算法,但此方法通常不使用递归函数实现。

DFS版代码

 1 #include <stdio.h>
 2 #include <string.h>
 3 
 4 /*Header which contains the output function*/
 5 #include "prnt_route.h"
 6 
 7 int    n,m;
 8 int    visited[1100][1100];
 9 struct PII    from[1100][1100];
10 /*Save the route.*/
11 
12 const int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
13 
14 char    Map[1100][1100];
15 
16 int    Dfs(const int Sx,const int Sy, const int Tx,const int Ty)
17 {
18     if(Sx==Tx && Sy==Ty) return 1;
19     int i;
20     for(i=0;i<4;++i)/*Search four directions*/
21     {
22         int tx=Sx+dx[i],ty=Sy+dy[i];/*tx,ty refers to the next grid.*/
23         if(tx>=0 && ty>=0 && tx<n && ty<m && 
24             !visited[tx][ty] && Map[tx][ty]!='#')
25         /*check if (tx,ty) is reachable*/
26         {
27             visited[tx][ty]=1;
28             if(Dfs(tx,ty,Tx,Ty))
29             {
30                 /*Route is found.*/
31                 from[tx][ty]=make_pair(Sx,Sy);
32                 return 1;
33             }
34         }
35     }
36     return 0;
37 }
38 
39 int main()
40 {
41     freopen("in.txt","r",stdin);
42     freopen("out.txt","w",stdout);
43     int i,j,Sx,Sy,Tx,Ty;
44     scanf("%d%d",&n,&m);
45     Sx=Sy=1,Tx=n-2,Ty=m-2;
46     for(i=0;i<n;++i) scanf("%s",Map[i]);
47     
48     /*Find the starting and ending points.*/
49     for(i=0;i<n;++i)
50         for(j=0;j<m;++j)
51             if(Map[i][j]=='S') Sx=i,Sy=j;
52             else if(Map[i][j]=='T') Tx=i,Ty=j;
53             
54     /*Dfs will return 1 if a solution is found, 0 otherwise.*/
55     if(Dfs(Sx,Sy,Tx,Ty)) Print_Ans(Sx,Sy,Tx,Ty);
56     else printf("No Solution.\n");
57     return 0;
58 }
View Code

BFS版代码

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 
 5 /*Header contains the outout function*/
 6 #include "prnt_route.h"
 7 
 8 int n,m;
 9 int visited[1100][1100];
10 struct PII  from[1100][1100];
11 /*Save the route*/
12 
13 char    Map[1100][1100];
14 
15 int Bfs(const int Sx,const int Sy, const int Tx,const int Ty)
16 {
17     struct PII Q[(n+5)*(m+5)];/*Queue for Bfs*/
18     int front=0,back=0;/*head and tail pointer of the queue*/
19     memset(visited,0,sizeof(visited));
20     memset(from,0,sizeof(from));
21     Q[back++]=make_pair(Sx,Sy);/*push the starting point*/ 
22     visited[Sx][Sy]=1;
23     while(front!=back && !visited[Tx][Ty])
24     {
25         struct PII t=Q[front++];/*Pop out*/
26         /*Search four directions*/
27         if(t.x>0 && !visited[t.x-1][t.y] && Map[t.x-1][t.y]!='#')/*up*/
28         {
29             Q[back++]=make_pair(t.x-1,t.y);/*push*/
30             visited[t.x-1][t.y]=1;
31             from[t.x-1][t.y]=make_pair(t.x,t.y);
32         }
33         if(t.x<n-1 && !visited[t.x+1][t.y] && Map[t.x+1][t.y]!='#')/*down*/
34         {
35             Q[back++]=make_pair(t.x+1,t.y);/*push*/
36             visited[t.x+1][t.y]=1;
37             from[t.x+1][t.y]=make_pair(t.x,t.y);
38         }
39         if(t.y>0 && !visited[t.x][t.y-1] && Map[t.x][t.y-1]!='#')/*left*/
40         {
41             Q[back++]=make_pair(t.x,t.y-1);/*push*/
42             visited[t.x][t.y-1]=1;
43             from[t.x][t.y-1]=make_pair(t.x,t.y);
44         }
45         if(t.y<m-1 && !visited[t.x][t.y+1] && Map[t.x][t.y+1]!='#')/*right*/
46         {
47             Q[back++]=make_pair(t.x,t.y+1);/*push*/
48             visited[t.x][t.y+1]=1;
49             from[t.x][t.y+1]=make_pair(t.x,t.y);
50         }
51     }
52     return visited[Tx][Ty];
53 }
54 
55 int main()
56 {
57     freopen("in.txt","r",stdin);
58     freopen("out.txt","w",stdout);
59     int i,j,Sx,Sy,Tx,Ty;
60     scanf("%d%d",&n,&m);
61     Sx=Sy=1,Tx=n-2,Ty=m-2;
62     for(i=0;i<n;++i) scanf("%s",Map[i]);
63     
64     /*Find the starting and ending points*/
65     for(i=0;i<n;++i)
66         for(j=0;j<m;++j)
67             if(Map[i][j]=='S') Sx=i,Sy=j;
68             else if(Map[i][j]=='T') Tx=i,Ty=j;
69             
70     /*Bfs will return 1 if route is found.*/
71     if(Bfs(Sx,Sy,Tx,Ty)) Print_Ans(Sx,Sy,Tx,Ty);
72     else printf("No Solution.\n");
73     return 0;
74 }
View Code

print_route.h(两篇代码公用)

 1 /*Output function*/
 2 
 3 #include <stdio.h>
 4 
 5 struct PII { int x,y; };/*coordinate container*/
 6 struct PII make_pair(const int x,const int y)
 7 { struct PII t; t.x=x,t.y=y; return t; }
 8 
 9 extern int    n,m;
10 extern int    visited[1100][1100];
11 extern struct PII    from[1100][1100];
12 
13 extern char    Map[1100][1100];
14 
15 void    Print_Ans(const int Sx,const int Sy,const int Tx,const int Ty)
16 {
17     int x=Tx,y=Ty,dir=0,td,i,j,tempx,tempy;
18     /*'dir' is the current direction, while 'td' is the last direcion.*/
19     while(x!=Sx || y!=Sy)
20     {
21         /*judge the direction*/
22         if(from[x][y].y==y && from[x][y].x==x+1) Map[x][y]='^',td=0;
23         if(from[x][y].y==y && from[x][y].x==x-1) Map[x][y]='V',td=1;
24         if(from[x][y].x==x && from[x][y].y==y+1) Map[x][y]='<',td=2;
25         if(from[x][y].x==x && from[x][y].y==y-1) Map[x][y]='>',td=3;
26         /*decide which conner character should be output.*/
27         if(dir==0 && td==3) Map[x][y]='}';
28         if(dir==2 && td==1) Map[x][y]='}';
29         if(dir==3 && td==1) Map[x][y]='{';
30         if(dir==0 && td==2) Map[x][y]='{';
31         if(dir==1 && td==3) Map[x][y]=']';
32         if(dir==2 && td==0) Map[x][y]=']';
33         if(dir==3 && td==0) Map[x][y]='[';
34         if(dir==1 && td==2) Map[x][y]='[';
35         tempx=x,tempy=y; dir=td;
36         x=from[tempx][tempy].x;
37         y=from[tempx][tempy].y;
38     }
39     Map[Sx][Sy]='S';
40     Map[Tx][Ty]='T';
41 
42     for(i=0;i<n;++i)
43     {
44         for(j=0;j<m;++j)
45         {
46             /*output with special chars.*/
47             if(Map[i][j]=='#') printf("");
48             else if(Map[i][j]=='.') printf("  ");
49             else if(Map[i][j]=='^') printf("");
50             else if(Map[i][j]=='V') printf("");
51             else if(Map[i][j]=='<') printf("");
52             else if(Map[i][j]=='>') printf("");
53             else if(Map[i][j]=='+') printf("");
54             else if(Map[i][j]=='[') printf("");
55             else if(Map[i][j]==']') printf("");
56             else if(Map[i][j]=='{') printf("");
57             else if(Map[i][j]=='}') printf("");
58             else printf("");
59         }
60         printf("\n");
61     }
62     return ;
63 }
View Code

标准ascii字符版print_route.h

 1 #include <stdio.h>
 2 
 3 struct PII { int x,y; };
 4 struct PII make_pair(const int x,const int y)
 5 { struct PII t; t.x=x,t.y=y; return t; }
 6 
 7 extern int    n,m;
 8 extern int    visited[1100][1100];
 9 extern struct PII    from[1100][1100];
10 
11 extern char    Map[1100][1100];
12 
13 void    Print_Ans(const int Sx,const int Sy,const int Tx,const int Ty)
14 {
15     int x=Tx,y=Ty,dir=0,td,i,tempx,tempy;
16     while(x!=Sx || y!=Sy)
17     {
18         if(from[x][y].y==y && from[x][y].x==x+1) Map[x][y]='|',td=0;
19         if(from[x][y].y==y && from[x][y].x==x-1) Map[x][y]='|',td=1;
20         if(from[x][y].x==x && from[x][y].y==y+1) Map[x][y]='-',td=2;
21         if(from[x][y].x==x && from[x][y].y==y-1) Map[x][y]='-',td=3;
22         if(dir==0 && td==3) Map[x][y]='+';
23         if(dir==2 && td==1) Map[x][y]='+';
24         if(dir==3 && td==1) Map[x][y]='+';
25         if(dir==0 && td==2) Map[x][y]='+';
26         if(dir==1 && td==3) Map[x][y]='+';
27         if(dir==2 && td==0) Map[x][y]='+';
28         if(dir==3 && td==0) Map[x][y]='+';
29         if(dir==1 && td==2) Map[x][y]='+';
30         tempx=x,tempy=y; dir=td;
31         x=from[tempx][tempy].x;
32         y=from[tempx][tempy].y;
33     }
34     Map[Sx][Sy]='S';
35     Map[Tx][Ty]='T';
36 
37     for(i=0;i<n;++i)printf("%s\n",Map[i]);
38     return ;
39 }
View Code

 

【地图生成器】

方法,使用DFS,每次随机一个方向进行扩展。但这样可能导致一条路径过长,岔路过短。

所以加入三个参数:

  1.搜索过程中有一定几率保持上一次的方向,称为RATE_KEEP_DIR

  2.搜索过程中有一定几率停止当前道路的搜索,直接return,这个参数称为RETURN_RATE

  3.每条链有一个最大长度,称为TWIST_RATE

通过修改这三个参数,可以改变地图的性态。

 

生成器代码使用C++,编译需要加-std=c++11参数,代码如下

 1 //Compile with -std=c++11
 2 #include <bits/stdc++.h>
 3 
 4 using namespace std;
 5 
 6 const int RATE_KEEP_DIR=000;
 7 const int TWIST_RATE=10;
 8 const int RETURN_RATE=100;
 9 
10 int n,m,Sx,Sy,Tx,Ty,Max;
11 char    Map[1100][1100];
12 typedef pair<int,int>   PII;
13 const int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
14 const int Dx[4]={-2,0,2,0},Dy[4]={0,2,0,-2};
15 
16 mt19937     RND(time(0));
17 
18 //Check if (x,y) has a neighbour can go. 
19 bool    Check(const int x,const int y)
20 {
21     for(int i=0;i<4;++i)
22     {
23         int nx=x+dx[i],ny=y+dy[i],Nx=x+Dx[i],Ny=y+Dy[i];
24         if(Nx>=0 && Nx<n && Ny>=0 && Ny<m && (Map[Nx][Ny]=='#' && Map[nx][ny]=='#'))return true;
25     } return false;
26 }
27 
28 void    Dfs(const int x,const int y,const int depth,int Lim,const int last_dir)
29 {
30     if(depth>Max)Tx=x,Ty=y,Max=depth;//find a longest route
31     if(depth>Lim) return ;
32     Map[x][y]='.';
33     while(Check(x,y))
34     {
35         int t=RND()%4;//random direction
36         if(RND()%1000<RATE_KEEP_DIR) t=last_dir;//chance of keeping direction. 
37         int nx=x+dx[t],ny=y+dy[t],Nx=x+Dx[t],Ny=y+Dy[t];
38         if(nx<0 || nx>n-1 || ny<0 || ny>m-1 || Map[nx][ny]!='#')continue;
39         if(Nx<0 || Nx>n-1 || Ny<0 || Ny>m-1 || Map[Nx][Ny]!='#')continue;
40         if(Nx==0 || Nx==n-1 || Ny==0 || Ny==m-1) { Map[nx][ny]='.'; continue; }
41         Map[nx][ny]='.'; Map[Nx][Ny]='.';
42         Dfs(Nx,Ny,depth+1,Lim,t);
43         
44         //chance of returning directly, without expanding, for more branch roads 
45         if((int)(RND()%1000)<(min(n,m)<100?0:RETURN_RATE)) return ;
46         
47         Lim=depth+max(min(n,m)/TWIST_RATE,5);
48     }
49     return ;
50 }
51 
52 int main()
53 {
54     freopen("in.txt","w",stdout);
55     scanf("%d%d",&n,&m);
56     printf("%d %d\n",n,m);
57     for(int i=0;i<n;++i) for(int j=0;j<m;++j) Map[i][j]='#';
58     Sx=Sy=1;
59     // the length limit of each branch road.
60     Dfs(Sx,Sy,0,max(min(n,m)/TWIST_RATE,5),2);
61     //set starting and ending points.
62     Map[Sx][Sy]='S';
63     Map[Tx][Ty]='T';
64     for(int i=0;i<n;++i) printf("%s\n",Map[i]);
65     return 0;
66 }
View Code

以下C++代码可以将生成器生成的地图转化为全角符号,便于查看

 1 #include <bits/stdc++.h>
 2 
 3 int n,m;
 4 char    Map[1100][1100];
 5 
 6 using namespace std;
 7 
 8 int main()
 9 {
10     freopen("in.txt","r",stdin);
11     freopen("view.txt","w",stdout);
12     scanf("%d%d",&n,&m);
13     for(int i=0;i<n;++i)
14         scanf("%s",Map[i]);
15     for(int i=0;i<n;++i)
16     {
17         for(int j=0;j<m;++j)
18         {
19             if(Map[i][j]=='#') printf("");
20             else if(Map[i][j]=='.') printf("  ");
21             else printf("");
22         }
23         printf("\n");
24     }
25     return 0;
26 }
View Code

 

posted @ 2018-07-10 23:59  Gster  阅读(1538)  评论(0编辑  收藏  举报