[ C语言 ] 迷宫 迷宫生成器 [ 递归与搜索 ]
【原创】转载请注明出处 【浙江大学 程序设计专题】
【地图求解器】
本题目要求输入一个迷宫地图,输出从起点到终点的路线。
基本思路是从起点(Sx,Sy)每次枚举该格子上下左右四个方向,直到走到终点(Tx,Ty)。
方法一:如果使用递归方法,则可以使用深度优先搜索算法,但此方法不能保证答案步数最优。
方法二: 如果要求答案步数最少,则使用广度优先搜索算法,但此方法通常不使用递归函数实现。
DFS版代码
#include <stdio.h>
#include <string.h> /*Header which contains the output function*/
#include "prnt_route.h" int n,m;
int visited[][];
struct PII from[][];
/*Save the route.*/ const int dx[]={-,,,},dy[]={,,,-}; char Map[][]; int Dfs(const int Sx,const int Sy, const int Tx,const int Ty)
{
if(Sx==Tx && Sy==Ty) return ;
int i;
for(i=;i<;++i)/*Search four directions*/
{
int tx=Sx+dx[i],ty=Sy+dy[i];/*tx,ty refers to the next grid.*/
if(tx>= && ty>= && tx<n && ty<m &&
!visited[tx][ty] && Map[tx][ty]!='#')
/*check if (tx,ty) is reachable*/
{
visited[tx][ty]=;
if(Dfs(tx,ty,Tx,Ty))
{
/*Route is found.*/
from[tx][ty]=make_pair(Sx,Sy);
return ;
}
}
}
return ;
} int main()
{
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
int i,j,Sx,Sy,Tx,Ty;
scanf("%d%d",&n,&m);
Sx=Sy=,Tx=n-,Ty=m-;
for(i=;i<n;++i) scanf("%s",Map[i]); /*Find the starting and ending points.*/
for(i=;i<n;++i)
for(j=;j<m;++j)
if(Map[i][j]=='S') Sx=i,Sy=j;
else if(Map[i][j]=='T') Tx=i,Ty=j; /*Dfs will return 1 if a solution is found, 0 otherwise.*/
if(Dfs(Sx,Sy,Tx,Ty)) Print_Ans(Sx,Sy,Tx,Ty);
else printf("No Solution.\n");
return ;
}
BFS版代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /*Header contains the outout function*/
#include "prnt_route.h" int n,m;
int visited[][];
struct PII from[][];
/*Save the route*/ char Map[][]; int Bfs(const int Sx,const int Sy, const int Tx,const int Ty)
{
struct PII Q[(n+)*(m+)];/*Queue for Bfs*/
int front=,back=;/*head and tail pointer of the queue*/
memset(visited,,sizeof(visited));
memset(from,,sizeof(from));
Q[back++]=make_pair(Sx,Sy);/*push the starting point*/
visited[Sx][Sy]=;
while(front!=back && !visited[Tx][Ty])
{
struct PII t=Q[front++];/*Pop out*/
/*Search four directions*/
if(t.x> && !visited[t.x-][t.y] && Map[t.x-][t.y]!='#')/*up*/
{
Q[back++]=make_pair(t.x-,t.y);/*push*/
visited[t.x-][t.y]=;
from[t.x-][t.y]=make_pair(t.x,t.y);
}
if(t.x<n- && !visited[t.x+][t.y] && Map[t.x+][t.y]!='#')/*down*/
{
Q[back++]=make_pair(t.x+,t.y);/*push*/
visited[t.x+][t.y]=;
from[t.x+][t.y]=make_pair(t.x,t.y);
}
if(t.y> && !visited[t.x][t.y-] && Map[t.x][t.y-]!='#')/*left*/
{
Q[back++]=make_pair(t.x,t.y-);/*push*/
visited[t.x][t.y-]=;
from[t.x][t.y-]=make_pair(t.x,t.y);
}
if(t.y<m- && !visited[t.x][t.y+] && Map[t.x][t.y+]!='#')/*right*/
{
Q[back++]=make_pair(t.x,t.y+);/*push*/
visited[t.x][t.y+]=;
from[t.x][t.y+]=make_pair(t.x,t.y);
}
}
return visited[Tx][Ty];
} int main()
{
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
int i,j,Sx,Sy,Tx,Ty;
scanf("%d%d",&n,&m);
Sx=Sy=,Tx=n-,Ty=m-;
for(i=;i<n;++i) scanf("%s",Map[i]); /*Find the starting and ending points*/
for(i=;i<n;++i)
for(j=;j<m;++j)
if(Map[i][j]=='S') Sx=i,Sy=j;
else if(Map[i][j]=='T') Tx=i,Ty=j; /*Bfs will return 1 if route is found.*/
if(Bfs(Sx,Sy,Tx,Ty)) Print_Ans(Sx,Sy,Tx,Ty);
else printf("No Solution.\n");
return ;
}
print_route.h(两篇代码公用)
/*Output function*/ #include <stdio.h> struct PII { int x,y; };/*coordinate container*/
struct PII make_pair(const int x,const int y)
{ struct PII t; t.x=x,t.y=y; return t; } extern int n,m;
extern int visited[][];
extern struct PII from[][]; extern char Map[][]; void Print_Ans(const int Sx,const int Sy,const int Tx,const int Ty)
{
int x=Tx,y=Ty,dir=,td,i,j,tempx,tempy;
/*'dir' is the current direction, while 'td' is the last direcion.*/
while(x!=Sx || y!=Sy)
{
/*judge the direction*/
if(from[x][y].y==y && from[x][y].x==x+) Map[x][y]='^',td=;
if(from[x][y].y==y && from[x][y].x==x-) Map[x][y]='V',td=;
if(from[x][y].x==x && from[x][y].y==y+) Map[x][y]='<',td=;
if(from[x][y].x==x && from[x][y].y==y-) Map[x][y]='>',td=;
/*decide which conner character should be output.*/
if(dir== && td==) Map[x][y]='}';
if(dir== && td==) Map[x][y]='}';
if(dir== && td==) Map[x][y]='{';
if(dir== && td==) Map[x][y]='{';
if(dir== && td==) Map[x][y]=']';
if(dir== && td==) Map[x][y]=']';
if(dir== && td==) Map[x][y]='[';
if(dir== && td==) Map[x][y]='[';
tempx=x,tempy=y; dir=td;
x=from[tempx][tempy].x;
y=from[tempx][tempy].y;
}
Map[Sx][Sy]='S';
Map[Tx][Ty]='T'; for(i=;i<n;++i)
{
for(j=;j<m;++j)
{
/*output with special chars.*/
if(Map[i][j]=='#') printf("█");
else if(Map[i][j]=='.') printf(" ");
else if(Map[i][j]=='^') printf("↑");
else if(Map[i][j]=='V') printf("↓");
else if(Map[i][j]=='<') printf("←");
else if(Map[i][j]=='>') printf("→");
else if(Map[i][j]=='+') printf("╋");
else if(Map[i][j]=='[') printf("┏");
else if(Map[i][j]==']') printf("┓");
else if(Map[i][j]=='{') printf("┗");
else if(Map[i][j]=='}') printf("┛");
else printf("☆");
}
printf("\n");
}
return ;
}
标准ascii字符版print_route.h
#include <stdio.h> struct PII { int x,y; };
struct PII make_pair(const int x,const int y)
{ struct PII t; t.x=x,t.y=y; return t; } extern int n,m;
extern int visited[][];
extern struct PII from[][]; extern char Map[][]; void Print_Ans(const int Sx,const int Sy,const int Tx,const int Ty)
{
int x=Tx,y=Ty,dir=,td,i,tempx,tempy;
while(x!=Sx || y!=Sy)
{
if(from[x][y].y==y && from[x][y].x==x+) Map[x][y]='|',td=;
if(from[x][y].y==y && from[x][y].x==x-) Map[x][y]='|',td=;
if(from[x][y].x==x && from[x][y].y==y+) Map[x][y]='-',td=;
if(from[x][y].x==x && from[x][y].y==y-) Map[x][y]='-',td=;
if(dir== && td==) Map[x][y]='+';
if(dir== && td==) Map[x][y]='+';
if(dir== && td==) Map[x][y]='+';
if(dir== && td==) Map[x][y]='+';
if(dir== && td==) Map[x][y]='+';
if(dir== && td==) Map[x][y]='+';
if(dir== && td==) Map[x][y]='+';
if(dir== && td==) Map[x][y]='+';
tempx=x,tempy=y; dir=td;
x=from[tempx][tempy].x;
y=from[tempx][tempy].y;
}
Map[Sx][Sy]='S';
Map[Tx][Ty]='T'; for(i=;i<n;++i)printf("%s\n",Map[i]);
return ;
}
【地图生成器】
方法,使用DFS,每次随机一个方向进行扩展。但这样可能导致一条路径过长,岔路过短。
所以加入三个参数:
1.搜索过程中有一定几率保持上一次的方向,称为RATE_KEEP_DIR
2.搜索过程中有一定几率停止当前道路的搜索,直接return,这个参数称为RETURN_RATE
3.每条链有一个最大长度,称为TWIST_RATE
通过修改这三个参数,可以改变地图的性态。
生成器代码使用C++,编译需要加-std=c++11参数,代码如下
//Compile with -std=c++11
#include <bits/stdc++.h> using namespace std; const int RATE_KEEP_DIR=;
const int TWIST_RATE=;
const int RETURN_RATE=; int n,m,Sx,Sy,Tx,Ty,Max;
char Map[][];
typedef pair<int,int> PII;
const int dx[]={-,,,},dy[]={,,,-};
const int Dx[]={-,,,},Dy[]={,,,-}; mt19937 RND(time()); //Check if (x,y) has a neighbour can go.
bool Check(const int x,const int y)
{
for(int i=;i<;++i)
{
int nx=x+dx[i],ny=y+dy[i],Nx=x+Dx[i],Ny=y+Dy[i];
if(Nx>= && Nx<n && Ny>= && Ny<m && (Map[Nx][Ny]=='#' && Map[nx][ny]=='#'))return true;
} return false;
} void Dfs(const int x,const int y,const int depth,int Lim,const int last_dir)
{
if(depth>Max)Tx=x,Ty=y,Max=depth;//find a longest route
if(depth>Lim) return ;
Map[x][y]='.';
while(Check(x,y))
{
int t=RND()%;//random direction
if(RND()%<RATE_KEEP_DIR) t=last_dir;//chance of keeping direction.
int nx=x+dx[t],ny=y+dy[t],Nx=x+Dx[t],Ny=y+Dy[t];
if(nx< || nx>n- || ny< || ny>m- || Map[nx][ny]!='#')continue;
if(Nx< || Nx>n- || Ny< || Ny>m- || Map[Nx][Ny]!='#')continue;
if(Nx== || Nx==n- || Ny== || Ny==m-) { Map[nx][ny]='.'; continue; }
Map[nx][ny]='.'; Map[Nx][Ny]='.';
Dfs(Nx,Ny,depth+,Lim,t); //chance of returning directly, without expanding, for more branch roads
if((int)(RND()%)<(min(n,m)<?:RETURN_RATE)) return ; Lim=depth+max(min(n,m)/TWIST_RATE,);
}
return ;
} int main()
{
freopen("in.txt","w",stdout);
scanf("%d%d",&n,&m);
printf("%d %d\n",n,m);
for(int i=;i<n;++i) for(int j=;j<m;++j) Map[i][j]='#';
Sx=Sy=;
// the length limit of each branch road.
Dfs(Sx,Sy,,max(min(n,m)/TWIST_RATE,),);
//set starting and ending points.
Map[Sx][Sy]='S';
Map[Tx][Ty]='T';
for(int i=;i<n;++i) printf("%s\n",Map[i]);
return ;
}
以下C++代码可以将生成器生成的地图转化为全角符号,便于查看
#include <bits/stdc++.h> int n,m;
char Map[][]; using namespace std; int main()
{
freopen("in.txt","r",stdin);
freopen("view.txt","w",stdout);
scanf("%d%d",&n,&m);
for(int i=;i<n;++i)
scanf("%s",Map[i]);
for(int i=;i<n;++i)
{
for(int j=;j<m;++j)
{
if(Map[i][j]=='#') printf("█");
else if(Map[i][j]=='.') printf(" ");
else printf("☆");
}
printf("\n");
}
return ;
}
[ C语言 ] 迷宫 迷宫生成器 [ 递归与搜索 ]的更多相关文章
- AI-随机迷宫&迷宫求解
本文记录了,人工智能中简单的搜索策略中的路径搜索策略中的A*算法,来实现迷宫寻路的问题.(这只是一次本人的课外作业) 完整的程序源码已经发送到我的Git.这里只记录了我的思路和感想以及收获. 产生随机 ...
- python 递归深度优先搜索与广度优先搜索算法模拟实现
一.递归原理小案例分析 (1)# 概述 递归:即一个函数调用了自身,即实现了递归 凡是循环能做到的事,递归一般都能做到! (2)# 写递归的过程 1.写出临界条件2.找出这一次和上一次关系3.假设当前 ...
- fastposter发布1.4.2 跨语言的海报生成器
fastposter发布1.4.2 跨语言的海报生成器 fastposter发布1.4.2 跨语言的海报生成器,一分钟完成海报开发 future: 完善docker镜像 引入异步asyncio 升级p ...
- [迷宫中的算法实践]迷宫生成算法——递归分割算法
Recursive division method Mazes can be created with recursive division, an algorithm which wo ...
- ytu 1980:小鼠迷宫问题(DFS 深度优先搜索)
小鼠迷宫问题 Time Limit: 2 Sec Memory Limit: 64 MB Submit: 1 Solved: 1 [Submit][Status][Web Board] Desc ...
- [Swust OJ 409]--小鼠迷宫问题(BFS+记忆化搜索)
题目链接:http://acm.swust.edu.cn/problem/409/ Time limit(ms): 1000 Memory limit(kb): 65535 Description ...
- poj3984《迷宫问题》暑假集训-搜索进阶
K - 迷宫问题 Crawling in process... Crawling failed Time Limit:1000MS Memory Limit:65536KB 64bit ...
- BZOJ2246 [SDOI2011]迷宫探险 【记忆化搜索dp + 概率】
题目 输入格式 输出格式 仅包含一个数字,表示在执行最优策略时,人物活着走出迷宫的概率.四舍五入保留3位小数. 输入样例 4 3 3 2 .$. A#B A#C @@@ 143 37 335 85 9 ...
- POJ 3984:迷宫问题 bfs+递归输出路径
迷宫问题 Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 11844 Accepted: 7094 Description ...
随机推荐
- .net 环境下c# 通信
.net环境下通信主要掌握 通信协议(UDP&TCP). 网络抓包工具().:使用方法 点对点通信,IP组播,广播通信 c#中结构体转为字节流方式 c#结构体与c++结构体转换对应关系 开源的 ...
- TCP协议三次握手和四次握手
前言 先说一下IP协议和TCP协议,IP协议是无连接的通信协议,IP不会占用两个设备之间通信的线路,IP实际上主要负责将每个数据包路由至目的地,但是IP协议并没有能够确保数据包是否到达,传过去的数据包 ...
- 浅谈网上的zoomlistview存在的问题
最近项目主要是做一个类似wps文档阅历的功能,以列表的形式显示文档,并且需要实现缩放平移.而网上关于此类功能的实现主要是通过自定义的listview实现的,类名为ZoomListView. 网上的zo ...
- Farseer.net轻量级ORM开源框架 V1.x 入门篇:新版本说明
导航 目 录:Farseer.net轻量级ORM开源框架 目录 上一篇:没有了 下一篇:Farseer.net轻量级ORM开源框架 V1.x 入门篇:数据库配置 前言 V1.x版本终于到来了.本次 ...
- (转)淘淘商城系列——SSM框架整合之Dao层整合
http://blog.csdn.net/yerenyuan_pku/article/details/72721093 一个项目中往往有三层即Dao层.Service层和Web层,看标题就知道了,本文 ...
- 【转】用jquery编写动态的返回顶部特效
jquery代码: function gotoTop(min_height){ //预定义返回顶部的html代码,它的css样式默认为不显示 var gotoTop_html = '<div i ...
- JavaSE-17 泛型
学习要点 泛型接口 泛型类 泛型方法 多参数泛型类 泛型类的继承 泛型的定义 允许在定义类.接口.方法时使用类型形参,类型形参将会在声明变量.创建对象或者调用方法时候动态指定. 泛型接口 1 定义 ...
- NET SignaiR 实现消息的推送,并使用Push.js实现通知
一.使用背景 1. SignalR是什么? ASP.NET SignalR 是为 ASP.NET 开发人员提供的一个库,可以简化开发人员将实时 Web 功能添加到应用程序的过程.实时 Web 功能是指 ...
- 检查sql对象是否存在
SQL Server判断对象是否存在 1 判断数据库是否存在 Sql代码 if exists (select * from sys.databases where name = '数据库名') ...
- NOIP专题复习3 图论-强连通分量
目录 一.知识概述 二.典型例题 1.[HAOI2006]受欢迎的牛 2.校园网络[[USACO]Network of Schools加强版] 三.算法分析 (一)Tarjan算法 (二)解决问题 四 ...