“这是我参与8月更文挑战的第17天,活动详情查看:8月更文挑战”
关注我,以下内容持续更新
迷宫问题
从入口出发,按某一方向向前探索,若能走通(未走过的),即某处可以到达,则到达新点,否则试探下一方向;若该点所有的方向均没有通路,则沿原路返回到前一点,换下一个方向再继续试探,直到所有可能的通路都探索到,或找到一条通路,或无路可走又退回到入口点。退回到的“前一点”正是刚刚才被访问过的,具有“后进先出”的特性,需要用栈保存所能够到达的每一一点的下标及从该点前进的方向。
非递归方式
解题思路
我们规定: 0代表可以走;1代表不通;-1代表已走过。我们用二维数组(邻接矩阵)来表示迷宫,开始设置迷宫的四周一圈为1,即不可走.
在代码中先设置入口为已走过(matex[1][1] = -1),然后把它入栈,遍历时先从入口寻找它的四个方向是否有通路。代码中有两重循环,内层循环中:遍历当前点的前后左右四个方向进行尝试,判断是否可以走(matex[x][y] == 0),如果有一个方向可以走就把当前点入栈(push)并设置当前点已访问(matex[1][1] = -1),如果四个方向都判断完都不能走,说明此路不通,要回溯到上一个走通的格子,也就是跳出内层循环回到外层循环,让当前格子出桟(pop),在判断过程中把当前点入栈的时候,判断当前点是否是迷宫的终点(x == matrix.count-2 && y == matrix.count-2),如果是直接返回true 程序结束,最后桟中保存的是迷宫通路;外层循环判断桟是否为空,不为空才进行内层循环,如果为空直接返回false,即没有通路(没有通路就是无路可走又退回到入口点)
代码示例
-(void)mazeCase{
//用邻接矩阵表示迷宫: 1代表不通,0代表通
NSMutableArray<NSMutableArray<NSString*>*>*matrix = [@[
[@[@"1",@"1",@"1",@"1",@"1",@"1"] mutableCopy],
[@[@"1",@"0",@"0",@"1",@"1",@"1"] mutableCopy],
[@[@"1",@"0",@"0",@"0",@"0",@"1"] mutableCopy],
[@[@"1",@"0",@"1",@"1",@"1",@"1"] mutableCopy],
[@[@"1",@"0",@"0",@"0",@"0",@"1"] mutableCopy],
[@[@"1",@"1",@"1",@"1",@"1",@"1"] mutableCopy]]
mutableCopy];
printf("打印开始的迷宫\n");
[self showMatrix:matrix];
BOOL success = [self maze:matrix];
if (success) {
printf("迷宫可以走通\n");
}
}
-(void)showMatrix:(NSMutableArray<NSMutableArray<NSString*>*>*)matrix{
for (int i = 0; i<matrix.count; i++) {
for (int j = 0; j<matrix[i].count; j++) {
printf("%2d ",[matrix[i][j] intValue]);
}
printf("\n\n");
}
printf("本轮打印完毕\n");
}
-(BOOL)maze:(NSMutableArray<NSMutableArray<NSString*>*>*)matrix{
//用来存储四个方向的 x和y坐标,用CGPoint表示;x代表横向走,y代表纵向走
//规定方向的顺序:右->下->左->上
NSArray*ds = @[NSStringFromCGPoint(CGPointMake(0, 1)),NSStringFromCGPoint(CGPointMake(1, 0)),NSStringFromCGPoint(CGPointMake(0, -1)),NSStringFromCGPoint(CGPointMake(-1,0))];
MazeStack *stack = [MazeStack new];
int x = 1;
int y = 1;
int d = 0;//0代表第一个方向
matrix[x][y] = @"-1";//设置入口为已访问
[stack push:@[@(x),@(y),@(d)]];//先把入口入栈,遍历栈顶元素
NSArray*tmp = @[@(x),@(y),@(d)];//入口是当前格子
while (![stack isEmpty]) {
tmp = [stack pop];
d = 0;//出桟,从第一个方向走//因为每次回溯出桟后都要从第一个方向开始判断,所以要置 0;
while (d<4) {
CGPoint dp = CGPointFromString(ds[d]);
x = [tmp[0] intValue] + dp.x;
y = [tmp[1] intValue] + dp.y;
if ([matrix[x][y] intValue] == 0) {//如果通就入栈,继续往下走,继续走第一个方向即d=0;
matrix[x][y] = @"-1";
[stack push:@[@(x),@(y),@(d)]];
tmp = @[@(x),@(y),@(d)];
d = 0;//如果可以走通,下次继续从第一个方向走
[self showMatrix:matrix];//打印每一步的迷宫变化
if (x == matrix.count-2 && y == matrix[0].count-2) {
printf("迷宫走通了\n");
[stack showStack];//打印的桟有3个元素,前两个是坐标,第三个是方向
return true;
}
}else{//如果不通就判断下一个方向
d++;
}
}
}
printf("迷宫不通\n");
return NO;
}
代码解读
① 规定: 0代表可以走;1代表不通;-1代表已走过。同时规定方向的顺序:右->下->左->上
② ds按顺序存储四个方向的x和y坐标,用CGPoint表示;x代表横向走,y代表纵向走;
③ 桟中存放的事数组,数组中有3个元素,前两个是x,y坐标,第三个是方向
④ 开始从入口开始走,把入口入栈并设置入口已访问,第一轮循环入口就是当前格子,循环中不断判断4个方向中是否有方向可走,如果都不可走,说明此路不通,出桟,回溯到走上一个格子,这时要重新从第一个方向开始走,循环此操作.
⑤ x == matrix.count-2 && y == matrix[0].count-2 就是最后的终点坐标
最初的迷宫
最后打印的走成功的迷宫
递归方式
-(BOOL)maze:(NSMutableArray<NSMutableArray<NSString*>*>*)matrix{
//用来存储四个方向的 x和y坐标,用CGPoint表示;x代表横向走,y代表纵向走
//规定方向的顺序:右->下->左->上
NSArray*ds = @[NSStringFromCGPoint(CGPointMake(0, 1)),NSStringFromCGPoint(CGPointMake(1, 0)),NSStringFromCGPoint(CGPointMake(0, -1)),NSStringFromCGPoint(CGPointMake(-1,0))];
//传入(1,1)从起点开始
return [self setWay:matrix x:1 y:1 ds:ds];
}
-(BOOL)setWay:(NSMutableArray<NSMutableArray<NSString*>*>*)matrix x:(int)x y:(int)y ds:(NSArray*)ds{
if (x == matrix.count-2 && y == matrix[0].count-2) {//如果能走到终点,直接返回YES;(终点肯定是可以走的,不用判断是否等于0)
matrix[x][y] = @"-1";//为了保证路径(matrix)的完整,加上这一句
return YES;
}
if (x<0 || x>matrix.count || y<0 || y>matrix[0].count) {
return NO;
}
//0代表可以走;1代表不通;-1代表已走过。
if ([matrix[x][y] intValue] == 0) {
matrix[x][y] = @"-1";
for (int i = 0; i<ds.count; i++) {
CGPoint dp = CGPointFromString(ds[i]);
int tmpX = x + dp.x;
int tmpY = y + dp.y;
if ([self setWay:matrix x:tmpX y:tmpY ds:ds]) {
return YES;
}
}
return NO;
}
return NO;
}
-(void)mazeCase{
//用邻接矩阵表示迷宫: 1代表不通,0代表通
NSMutableArray<NSMutableArray<NSString*>*>*matrix = [@[ [@[@"1",@"1",@"1",@"1",@"1",@"1"] mutableCopy],
[@[@"1",@"0",@"0",@"1",@"1",@"1"] mutableCopy],
[@[@"1",@"0",@"0",@"0",@"0",@"1"] mutableCopy],
[@[@"1",@"0",@"1",@"1",@"1",@"1"] mutableCopy],
[@[@"1",@"0",@"0",@"0",@"0",@"1"] mutableCopy],
[@[@"1",@"1",@"1",@"1",@"1",@"1"] mutableCopy]]
mutableCopy];
printf("打印开始的迷宫\n");
[self showMatrix:matrix];
//可以选择递归方式或者非递归方式
BOOL success = [self maze:matrix];
if (success) {
printf("迷宫可以走通\n");
}else{
printf("迷宫不可以走通\n");
}
printf("打印最后的迷宫\n");
[self showMatrix:matrix];
}
如果觉得我写的不错,请点个赞 关注我 您的支持是我更文最大的动力!