迷宮(棧回溯)
阿新 • • 發佈:2018-11-01
迷宮介紹
在生活中我們玩過很多種走迷宮的小遊戲,遊戲給了一個迷宮,這個迷宮中只有一個入口,我們要從這個入口一直走下去,直到找到出口,這裡出口可能是一個,也可能是多個。在這裡我簡單介紹三種實現起來由易到難的迷宮。
前提說明
我們這裡的座標是x軸正半軸向下伸展,y軸正半軸向右伸展
簡單迷宮
這是一種簡單迷宮,有一個入口和一個出口,我們從入口開始按照左上右下的順序進行嘗試走迷宮,如果都走不了,就開始進行回溯,前提是我們走過的路需要提前標記,這樣回溯的時候就比較方便了。程式碼如下:
maze.h
#pragma once #include<stdio.h> #include<windows.h> #define ROWS 6 #define COLS 6 #define MAX 100 typedef struct { int x; int y; }Position; typedef Position datatype; typedef struct Stack{ datatype data[MAX]; int top; }Stack; void GoMaze();
maze.c
#define _CRT_SECURE_NO_WARNINGS 1 #include"maze.h" int maze[ROWS][COLS] = { { 0,0,0,0,0,0 }, { 0,0,1,0,0,0 }, { 0,0,1,0,0,0 }, { 0,0,1,1,1,0 }, { 0,0,1,0,1,1 }, { 0,0,1,0,0,0 } };//迷宮 void StackInit(Stack *stack) { stack->top = 0; } void StackPush(Stack *stack,datatype data) { stack->data[stack->top] = data; stack->top++; } void StackPop(Stack *stack) { stack->top--; } datatype StackTop(Stack *stack) { return stack->data[stack->top - 1]; } int IsExit(Position pos) { if (pos.y == COLS - 1) { return 1; } else return 0; } int CanPass(Position pos) { if (pos.x < 0 || pos.x >= ROWS) { return 0; } if (pos.y < 0 || pos.y >= COLS) { return 0; } if (maze[pos.x][pos.y] == 1) { return 1; } else return 0; } void PrintMaze() { for (int i = 0; i < ROWS; i++) { for (int j = 0; j < COLS; j++) { if (maze[i][j] == 1) { printf(" ");//路用空格表示 } else if (maze[i][j] == 0) { printf("■");//牆 } else { printf("◎");//走過的路進行標記方便回溯 } } printf("\n"); } } void GoMaze() { Stack stack; StackInit(&stack); Position entry = { 5,2 }; Position pos = entry; Position nextpos = pos; while (1) { //標記走過的位置 maze[pos.x][pos.y] = 2; system("cls");//列印前清屏 PrintMaze(); Sleep(300);//有間隔效果看起來會好一點 StackPush(&stack, pos); //當前是否走到出口 if (IsExit(pos)) { printf("找到出口了!\n"); return; } //沒有走到出口,按照左上右下的順序進行嘗試 nextpos.y -= 1; if (CanPass(nextpos)) { pos = nextpos; continue; } nextpos = pos; nextpos.x -= 1; if (CanPass(nextpos)) { pos = nextpos; continue; } nextpos = pos; nextpos.y += 1; if (CanPass(nextpos)) { pos = nextpos; continue; } nextpos = pos; nextpos.x += 1; if (CanPass(nextpos)) { pos = nextpos; continue; } //如果都走不了,出棧 StackPop(&stack); pos = StackTop(&stack); StackPop(&stack); } } void test() { GoMaze(); }
多通路迷宮(不帶環)
這是第二種迷宮,有一個入口,但是有兩個出口。如果還是用第一種簡單迷宮的方法,很顯然當它找到第一個出口的時候就會停下來,那麼我們如果想要把所有的路走找到,當找到第一個出口的時候我們把出口改成牆繼續找第二個出口,知道棧裡面一個元素都沒有的時候就結束。程式碼如下:
maze.h
#pragma once #include<stdio.h> #include<windows.h> #define ROWS 6 #define COLS 6 #define MAX 100 typedef struct { int x; int y; }Position; typedef Position datatype; typedef struct Stack{ datatype data[MAX]; int top; }Stack; void GoMaze();
maze.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"maze.h"
int maze[ROWS][COLS] = {
{ 0,0,0,0,0,0 },
{ 0,0,1,1,1,1 },
{ 0,0,1,0,0,0 },
{ 0,0,1,0,0,0 },
{ 0,0,1,1,1,1 },
{ 0,0,1,0,0,0 }
};
void StackInit(Stack *stack)
{
stack->top = 0;
}
void StackPush(Stack *stack,datatype data)
{
stack->data[stack->top] = data;
stack->top++;
}
void StackPop(Stack *stack)
{
stack->top--;
}
datatype StackTop(Stack *stack)
{
return stack->data[stack->top - 1];
}
int StackEmpty(Stack *stack)
{
if (stack->top == 0)
{
return 1;
}
else
return 0;
}
int IsExit(Position pos)
{
if (pos.y == COLS - 1)
{
return 1;
}
else
return 0;
}
int CanPass(Position pos)
{
if (pos.x < 0 || pos.x >= ROWS)
{
return 0;
}
if (pos.y < 0 || pos.y >= COLS)
{
return 0;
}
if (maze[pos.x][pos.y] == 1)
{
return 1;
}
else
return 0;
}
void PrintMaze()
{
for (int i = 0; i < ROWS; i++)
{
for (int j = 0; j < COLS; j++)
{
if (maze[i][j] == 1)
{
printf(" ");
}
else if (maze[i][j] == 0)
{
printf("■");
}
else
{
printf("◎");
}
}
printf("\n");
}
}
void GoMaze()
{
Stack stack;
StackInit(&stack);
Position entry = { 5,2 };
Position pos = entry;
Position nextpos = pos;
while (1)
{
//標記走過的位置
maze[pos.x][pos.y] = 2;
system("cls");//列印前清屏
PrintMaze();
Sleep(300);//有間隔效果看起來會好一點
StackPush(&stack, pos);
//當前是否走到出口
if (IsExit(pos))
{
printf("找到出口了!\n");
maze[pos.x][pos.y] = 0;
goto BACK;
}
//沒有走到出口,按照左上右下的順序進行嘗試
nextpos.y -= 1;
if (CanPass(nextpos))
{
pos = nextpos;
continue;
}
nextpos = pos;
nextpos.x -= 1;
if (CanPass(nextpos))
{
pos = nextpos;
continue;
}
nextpos = pos;
nextpos.y += 1;
if (CanPass(nextpos))
{
pos = nextpos;
continue;
}
nextpos = pos;
nextpos.x += 1;
if (CanPass(nextpos))
{
pos = nextpos;
continue;
}
BACK:
//如果都走不了,回溯
StackPop(&stack);
if (StackEmpty(&stack))
{
printf("結束\n");
return;
}
pos = StackTop(&stack);
StackPop(&stack);
}
}
void test()
{
GoMaze();
}
多通路迷宮(帶環)
這是第三種迷宮,仍然是多通路,不同的是,這次帶了環,和該如何是好呢?這時候我們可以遞迴的思想,利用遞迴的思想在回溯的時候可以不用判斷之前走過的路了。程式碼如下:
maze.h
#pragma once
#include<stdio.h>
#include<windows.h>
#define ROWS 6
#define COLS 6
#define MAX 100
typedef struct {
int x;
int y;
}Position;
typedef Position datatype;
typedef struct Stack{
datatype data[MAX];
int top;
}Stack;
void GoMazeR();
maze.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"maze.h"
int maze[ROWS][COLS] = {
{ 0,0,0,0,0,0 },
{ 0,1,1,1,1,0 },
{ 0,1,0,0,1,0 },
{ 0,1,0,0,1,0 },
{ 0,1,1,1,1,1 },
{ 0,1,0,0,0,0 }
};
void StackInit(Stack *stack)
{
stack->top = 0;
}
void StackPush(Stack *stack,datatype data)
{
stack->data[stack->top] = data;
stack->top++;
}
void StackPop(Stack *stack)
{
stack->top--;
}
datatype StackTop(Stack *stack)
{
return stack->data[stack->top - 1];
}
int StackEmpty(Stack *stack)
{
if (stack->top == 0)
{
return 1;
}
else
return 0;
}
int IsExit(Position pos)
{
if (pos.y == COLS - 1)
{
return 1;
}
else
return 0;
}
int CanPass(Position pos)
{
if (pos.x < 0 || pos.x >= ROWS)
{
return 0;
}
if (pos.y < 0 || pos.y >= COLS)
{
return 0;
}
if (maze[pos.x][pos.y] == 1)
{
return 1;
}
else
return 0;
}
void PrintMaze()
{
for (int i = 0; i < ROWS; i++)
{
for (int j = 0; j < COLS; j++)
{
if (maze[i][j] == 1)
{
printf(" ");
}
else if (maze[i][j] == 0)
{
printf("■");
}
else
{
printf("◎");
}
}
printf("\n");
}
}
void GoMazeR(Position pos)
{
Position nextpos = pos;
//標記走過的位置
maze[pos.x][pos.y] = 2;
system("cls");//列印前清屏
PrintMaze();
Sleep(300);//有間隔效果看起來會好一點
//當前是否走到出口
if (IsExit(pos))
{
maze[pos.x][pos.y] = 1;
printf("找到出口了!\n");
return;
}
//沒有走到出口,按照左上右下的順序進行嘗試
nextpos.y -= 1;
if (CanPass(nextpos))
{
GoMazeR(nextpos);
}
nextpos = pos;
nextpos.x -= 1;
if (CanPass(nextpos))
{
GoMazeR(nextpos);
}
nextpos = pos;
nextpos.y += 1;
if (CanPass(nextpos))
{
GoMazeR(nextpos);
}
nextpos = pos;
nextpos.x += 1;
if (CanPass(nextpos))
{
GoMazeR(nextpos);
}
//回溯之前把走過的路清空
maze[pos.x][pos.y] = 1;
}
void test()
{
Position entry = { 5,1 };
GoMazeR(entry);
}