迷宫求解

1) 求简单迷宫是否存在路径

描述

2) 求多出口迷宫的最短路径

描述

3) 求带环的多出口迷宫的最短路径

描述

seqstack.h:

#pragma once

#include <stddef.h>

#define FOR_MAZE
#ifdef FOR_MAZE
typedef struct Point{
    int row;
    int col;
}Point;
typedef Point SeqStackType;
#else
typedef char SeqStackType;
#endif

#define SEQ_STACK_SIZE 100

typedef struct SeqStack{
    SeqStackType data[SEQ_STACK_SIZE];
    size_t size;
}SeqStack;

void SeqStackInit(SeqStack* stack);     //初始化

void SeqStackDestroy(SeqStack* stack);      //销毁栈

void SeqStackPush(SeqStack* stack, SeqStackType value);     //入栈

void SeqStackPop(SeqStack* stack);      //出栈

int SeqStackTop(SeqStack* stack, SeqStackType* value);      //取栈顶元素

size_t SeqStackSize(SeqStack* stack);    //取栈的元素个数

void SeqStackAssign(SeqStack* from, SeqStack* to);     //栈赋值

#ifdef FOR_MAZE
void SeqStackDebugPrintPoint(SeqStack* stack, const char* msg);
#endif

seqstack.c:

#include "seqstack.h"
#include <string.h>

//初始化
void SeqStackInit(SeqStack* stack){
    if(stack == NULL){
        return;     //非法输入
    }
    stack->size = 0;
}

//销毁栈
void SeqStackDestroy(SeqStack* stack){
    if(stack == NULL){
        return;     //非法输入
    }
    stack->size = 0;
}

//入栈
void SeqStackPush(SeqStack* stack, SeqStackType value){
    if(stack == NULL){
        return;     //非法输入
    }
    if(stack->size >= SEQ_STACK_SIZE){
        return;     //栈已满
    }
    stack->data[stack->size++] = value;
}

//出栈
void SeqStackPop(SeqStack* stack){
    if(stack == NULL){
        return;     //非法输入
    }
    if(stack->size == 0){
        return;     //空栈
    }
    --stack->size;
}

//取栈顶元素
int SeqStackTop(SeqStack* stack, SeqStackType* value){
    if(stack == NULL || value == NULL){
        return 0;       //非法输入
    }
    if(stack->size == 0){
        return 0;       //空栈
    }
    *value = stack->data[stack->size - 1];
    return 1;
}

size_t SeqStackSize(SeqStack* stack){
    if(stack == NULL){
        return (size_t)-1;    //非法输入
    }
    return stack->size;
}

void SeqStackAssign(SeqStack* from, SeqStack* to){
    if(from == NULL || to == NULL){
        return;  //非法输入
    }
    to->size = from->size;
    size_t i = 0;
    for(; i < from->size; ++i){
        to->data[i] = from->data[i];
    }
   //memcpy(to, from, sizeof(SeqStack));
   //*to = *from;
}     

#ifdef FOR_MAZE
#include <stdio.h>
void SeqStackDebugPrintPoint(SeqStack* stack, const char* msg){
    if(stack == NULL){
        printf("stack == NULL\n");
        return;
    }
    printf("\n%s\n", msg);
    printf("[栈底]\n");
    size_t i = 0;
    for(; i < stack->size; ++i){
        printf("(%d, %d)\n", stack->data[i].row, stack->data[i].col);
    }
    printf("[栈顶]\n");
}
#endif


//以下是测试函数


#if 0
#include <stdio.h>

#define TEST_HEADER printf("\n=============================%s=======================\n",__FUNCTION__)

void SeqStackPrintChar(SeqStack* stack, const char* msg){
    if(stack == NULL){
        printf("stack = NULL\n");
    }
    printf("[%s]:\n",msg);
    printf("[栈底] ");
    size_t i = 0;
    for(; i < stack->size; ++i){
        printf("[%c] ", stack->data[i]);
    }
    printf("[栈顶]\n");
}

void TestInit(){
    TEST_HEADER;
    SeqStack stack;
    SeqStackInit(&stack);
    SeqStackPrintChar(&stack, "初始化空栈");
    printf("stack->size expect 0, actual %lu\n",stack.size);
}

void TestDestroy(){
    TEST_HEADER;
    SeqStack stack;
    SeqStackInit(&stack);
    SeqStackPush(&stack, 'a');
    SeqStackPush(&stack, 'b');
    SeqStackPush(&stack, 'c');
    SeqStackPush(&stack, 'd');
    SeqStackPrintChar(&stack, "入栈四个元素");
    SeqStackDestroy(&stack);
    SeqStackPrintChar(&stack, "销毁栈");
}

void TestPush(){
    TEST_HEADER;
    SeqStack stack;
    SeqStackInit(&stack);
    SeqStackPush(&stack, 'a');
    SeqStackPush(&stack, 'b');
    SeqStackPush(&stack, 'c');
    SeqStackPush(&stack, 'd');
    SeqStackPrintChar(&stack, "入栈四个元素");
}

void TestPop(){
    TEST_HEADER;
    SeqStack stack;
    SeqStackInit(&stack);
    SeqStackPush(&stack, 'a');
    SeqStackPush(&stack, 'b');
    SeqStackPush(&stack, 'c');
    SeqStackPush(&stack, 'd');
    SeqStackPrintChar(&stack, "入栈四个元素");
    SeqStackPop(&stack);
    SeqStackPrintChar(&stack, "出栈一个元素");
    SeqStackPop(&stack);
    SeqStackPrintChar(&stack, "再出栈一个元素");
    SeqStackPop(&stack);
    SeqStackPop(&stack);
    SeqStackPrintChar(&stack, "再出栈两个元素");
    SeqStackPop(&stack);
    SeqStackPrintChar(&stack, "尝试对空栈出栈");
}

void TestTop(){
    TEST_HEADER;
    SeqStack stack;
    SeqStackInit(&stack);
    SeqStackPush(&stack, 'a');
    SeqStackPush(&stack, 'b');
    SeqStackPush(&stack, 'c');
    SeqStackPush(&stack, 'd');
    SeqStackPrintChar(&stack, "入栈四个元素");
    char tmp = '\0';
    int ret = SeqStackTop(&stack, &tmp);
    printf("ret expect 1, actual %d\n",ret);
    printf("tmp expect d, actual %c\n",tmp);
}

int main(){
    TestInit();
    TestDestroy();
    TestPush();
    TestPop();
    TestTop();
    return 0;
}

#endif

maze.c:

#include <stdio.h>
#include "seqstack.h"

#define MAZE_ROW 6
#define MAZE_COL 6

typedef struct Maze{
    int map[MAZE_ROW][MAZE_COL];
}Maze;

void MazePrint(Maze* maze){
    if(maze == NULL){
        return;
    }
    size_t i = 0;
    for(; i<MAZE_ROW; ++i){
        size_t j = 0;
        for(; j<MAZE_COL; ++j){
            printf("%d ",maze->map[i][j]);
        }
        printf("\n");
    }
    printf("\n");
}

void MazeInit(Maze* maze){
    if(maze == NULL){
        return;
    }
    int map[MAZE_ROW][MAZE_COL] = {
        {0, 1, 0, 0, 0, 0},
        {0, 1, 1, 1, 0, 0},
        {0, 1, 0, 1, 1, 0},
        {0, 1, 1, 0, 0, 0},
        {0, 0, 1, 0, 0, 0},
        {0, 0, 1, 0, 0, 0}
    };
    size_t i = 0; 
    for(; i<MAZE_ROW; ++i){
        size_t j = 0;
        for(; j<MAZE_COL; ++j){
            maze->map[i][j] = map[i][j];
        }
    }
}

void MazeInitMultiExit(Maze* maze){
    if(maze == NULL){
        return;
    }
    int map[MAZE_ROW][MAZE_COL] = {
        {0, 1, 0, 0, 0, 0},
        {0, 1, 1, 1, 0, 0},
        {0, 1, 0, 1, 1, 1},
        {1, 1, 1, 0, 0, 0},
        {0, 0, 1, 0, 0, 0},
        {0, 0, 1, 0, 0, 0}
    };
    size_t i = 0; 
    for(; i<MAZE_ROW; ++i){
        size_t j = 0;
        for(; j<MAZE_COL; ++j){
            maze->map[i][j] = map[i][j];
        }
    }
}

void MazeInitMultiExitWithCycle(Maze* maze){
    if(maze == NULL){
        return;
    }
    int map[MAZE_ROW][MAZE_COL] = {
        {0, 1, 0, 0, 0, 0},
        {0, 1, 1, 1, 0, 0},
        {0, 1, 0, 1, 1, 1},
        {1, 1, 1, 1, 0, 0},
        {0, 0, 1, 0, 0, 0},
        {0, 0, 1, 0, 0, 0}
    };
    size_t i = 0; 
    for(; i<MAZE_ROW; ++i){
        size_t j = 0;
        for(; j<MAZE_COL; ++j){
            maze->map[i][j] = map[i][j];
        }
    }
}

int CanStay(Maze* maze,Point cur){
    if(maze == NULL){
        return 0;
    }
    //1.点在地图上
    if(cur.row < 0 || cur.row >= MAZE_ROW
       || cur.col < 0 || cur.col >= MAZE_COL){
        return 0;
    }
    //2.当前点对应值为1
    if(maze->map[cur.row][cur.col] == 1){
        return 1;
    }
    return 0;
}

void Mark(Maze* maze, Point cur){
    if(maze == NULL){
        return;
    }
    maze->map[cur.row][cur.col] = 2;
}

int IsExit(Point cur, Point entry){
    //1.点在地图边缘
    //2.不是入口点
    if(cur.row == 0 || cur.col == 0
       ||cur.row == MAZE_ROW - 1 || cur.col == MAZE_COL - 1){
        //在边缘上
        if(cur.row == entry.row && cur.col == entry.col){
            //是入口点
            return 0;
        }
        return 1;
    }
    return 0;
}

void _HasPath(Maze* maze,Point cur, Point entry){
    if(maze == NULL){
        return;
    }
    //1.判断该点是否可以落脚(点在地图上;位置的值是1)
    if(!CanStay(maze,cur)){
        return;
    }
    //2.标记走过的点
    Mark(maze,cur);
    //3.判定当前点是否是出口(落在边缘上;不是入口点)
    if(IsExit(cur, entry)){
        printf("找到了路径!\n");
        return;
    }
    //4.顺时针递归探测周围的点是否可以落脚
    Point up = cur;
    up.row -= 1;
    _HasPath(maze, up, entry);

    Point right = cur;
    right.col += 1;
    _HasPath(maze, right, entry);

    Point down = cur;
    down.row += 1;
    _HasPath(maze, down, entry);

    Point left = cur;
    left.col -= 1;
    _HasPath(maze, left, entry);

    //5.如果四个方向都探测完,直接返回
    return;
}

//使用递归的方法查找是否存在一条路径
void HasPath(Maze* maze,Point entry){
    if(maze == NULL){
        return;
    }
    Point cur = entry;
    _HasPath(maze, cur, entry);
}

//使用非递归方法查找是否存在一条路径
void HasPathByLoop(Maze* maze, Point entry){
    if(maze == NULL){
        return;
    }
    //1.判定入口点是否能落脚,如果不能,表示非法输入
    if(!CanStay(maze, entry)){
        return;      //入口点是非法点
    }
    //2.标记入口点走过了,将入口点入栈
    Mark(maze, entry);
    SeqStack stack;
    SeqStackInit(&stack);
    SeqStackPush(&stack, entry);
    //3.进入循环,取栈顶元素为当前点
    Point cur;
    while(SeqStackTop(&stack, &cur)){
        //4.判定当前点是否是出口(如果是出口,说明找到路径)
        if(IsExit(cur, entry)){
            printf("找到路径!\n");
            return;
        }
        //5.按照一定顺序判断当前点的四个邻接点是否能落脚
        Point up = cur;
        up.row -= 1;
        if(CanStay(maze, up)){
            //6.如果某个邻接点可以落脚,标记这个邻接点,并且把邻接点入栈,并且直接进入下一次循环
            Mark(maze, up);
            SeqStackPush(&stack, up);
            continue;
        }
        Point right = cur;
        right.col += 1;
        if(CanStay(maze, right)){
            Mark(maze, right);
            SeqStackPush(&stack, right);
            continue;
        }
        Point down = cur;
        down.row += 1;
        if(CanStay(maze, down)){
            Mark(maze, down);
            SeqStackPush(&stack, down);
            continue;
        }
        Point left = cur;
        left.col -= 1;
        if(CanStay(maze, left)){
            Mark(maze, left);
            SeqStackPush(&stack, left);
            continue;
        }
        //7.四个方向都探测完毕,把当前点出栈
        SeqStackPop(&stack);
    }
    return;
}

void _GetShortPath(Maze* maze, Point cur, Point entry, SeqStack* short_path, SeqStack* cur_path){
    //1.判断当前点是否能落脚
    if(!CanStay(maze, cur)){
        return;
    }
    //2.标记当前点,把当前点push到cur_path
    Mark(maze, cur);
    SeqStackPush(cur_path, cur);
    //3.判断当前点是否是出口,如果是出口
    if(IsExit(cur, entry)){
        //   a)比较当前点的 cur_path 和 short_path 的长短
        SeqStackDebugPrintPoint(cur_path, "找到一条路径!");
        if(SeqStackSize(cur_path) < SeqStackSize(short_path) || SeqStackSize(short_path) == 0){
           //   b)如果 cur_path 比 short_path 小,或者 short_path 为空,就用 cur_path 替换 short_path
           SeqStackAssign(cur_path, short_path);
           printf("当前路径是一条比较短的路径\n");
        }   
        //   c)让 cur_path 出栈,同时返回上一层栈帧
        SeqStackPop(cur_path);
        return;
    }
    //4.按照一定顺序,递归的调用该函数完成邻接点的判定
    Point up = cur;
    up.row -= 1;
    _GetShortPath(maze, up, entry, short_path, cur_path);

    Point right = cur;
    right.col += 1;
    _GetShortPath(maze, right, entry, short_path, cur_path);

    Point down = cur;
    down.row += 1;
    _GetShortPath(maze, down, entry, short_path, cur_path);

    Point left = cur;
    left.col -= 1;
    _GetShortPath(maze, left, entry, short_path, cur_path);
    //5.回溯到上一个位置,先将 cur_path 出栈,然后return
    SeqStackPop(cur_path);
    return;
}

void GetShortPath(Maze* maze,Point entry){
    SeqStack short_path;     //保存最短路径
    SeqStack cur_path;      //当前找到的路径是哪个
    SeqStackInit(&short_path);
    SeqStackInit(&cur_path);
    _GetShortPath(maze, entry, entry, &short_path, &cur_path);
    SeqStackDebugPrintPoint(&short_path, "最短路径是:");
}

int CanStayWithCycle(Maze* maze, Point cur, Point pre){
    //1.判定当前点是否在地图上,如果不在,就不能落脚
    if(cur.row < 0 || cur.row >= MAZE_ROW || cur.col < 0 || cur.col >= MAZE_COL){
        return 0;
    }
    //2.判定当前点的值是否为1,是1则一定能落脚
    int cur_value = maze->map[cur.row][cur.col];
    if(cur_value == 1){
        return 1;
    }
    //3.判定当前点的值和前一个点的值得大小
    //  满足 cur_value -1 > pre_value 时才能落脚
    if(pre.row >= 0 && pre.row < MAZE_ROW && pre.col >= 0 && pre.col < MAZE_COL){
        //判定pre合法
        int pre_value = maze->map[pre.row][pre.col];
        if(cur_value - 1 > pre_value){
            return 1;
        }
    }
    return 0;
}

void MarkWithCycle(Maze* maze, Point cur, Point pre){
    if(pre.row < 0 || pre.row >= MAZE_ROW || pre.col < 0 || pre.col >= MAZE_COL){
        //pre不合法
        maze->map[cur.row][cur.col] = 2;
        return;
    }
    int pre_value = maze->map[pre.row][pre.col];
    maze->map[cur.row][cur.col] = pre_value + 1;
}

void _GetShortPathWithCycle(Maze* maze, Point cur, Point pre, Point entry, SeqStack* short_path, SeqStack* cur_path){
    //1.判断当前点是否能落脚(判定落脚方式有变化)
    if(!CanStayWithCycle(maze, cur, pre)){
        return;
    }
    //2.如果能落脚,就标记当前点(标记方式也有变化),把当前点入栈
    MarkWithCycle(maze, cur, pre);
    SeqStackPush(cur_path, cur);
    //3.判断当前点是否是出口,如果是出口
    if(IsExit(cur, entry)){
        //   a)比较当前点的 cur_path 和 short_path 的长短
        SeqStackDebugPrintPoint(cur_path, "找到一条路径:");
        if(SeqStackSize(cur_path) < SeqStackSize(short_path) || SeqStackSize(short_path) == 0){
           //   b)如果 cur_path 比 short_path 小,或者 short_path 为空,就用 cur_path 替换 short_path
            SeqStackAssign(cur_path, short_path);
        }
        //   c)让 cur_path 出栈,并回溯
        SeqStackPop(cur_path);
        return;
    }
    //4.如果不是出口,以当前点为基准,探测四个方向,递归调用该函数
    Point up = cur;
    up.row -= 1;
    _GetShortPathWithCycle(maze, up, cur, entry, short_path, cur_path);

    Point right = cur;
    right.col += 1;
    _GetShortPathWithCycle(maze, right, cur, entry, short_path, cur_path);

    Point down = cur;
    down.row += 1;
    _GetShortPathWithCycle(maze, down, cur, entry, short_path, cur_path);

    Point left = cur;
    left.col -= 1;
    _GetShortPathWithCycle(maze, left, cur, entry, short_path, cur_path);
    //5.四个方向都探测完了,出栈,并回溯
    SeqStackPop(cur_path);
    return;
}

void GetShortPathWithCycle(Maze* maze,Point entry){
    SeqStack short_path;     //保存最短路径
    SeqStack cur_path;      //当前找到的路径是哪个
    SeqStackInit(&short_path);
    SeqStackInit(&cur_path);
    Point pre = {-1, -1};
    _GetShortPathWithCycle(maze, entry, pre, entry, &short_path, &cur_path);
    SeqStackDebugPrintPoint(&short_path, "最短路径是:");
}

////////////////////////////////////////////////////////////////////////////////
//以下是测试代码
////////////////////////////////////////////////////////////////////////////////

#define TEST_HEADER printf("\n=======%s========\n",__FUNCTION__)

void Test1(){
    TEST_HEADER;
    Maze maze;
    MazeInit(&maze);
    MazePrint(&maze);
}

void Test2(){
    TEST_HEADER;
    Maze maze;
    MazeInit(&maze);
    Point entry = {0,1};
    HasPath(&maze, entry);
    MazePrint(&maze);
}

void Test3(){
    TEST_HEADER;
    Maze maze;
    MazeInit(&maze);
    Point entry = {0, 1};
    HasPathByLoop(&maze, entry);
    MazePrint(&maze);
}

void Test4(){
    TEST_HEADER;
    Maze maze;
    MazeInitMultiExit(&maze);
    Point entry = {0, 1};
    GetShortPath(&maze, entry);
    MazePrint(&maze);
}

void Test5(){
    TEST_HEADER;
    Maze maze;
    MazeInitMultiExitWithCycle(&maze);
    Point entry = {0, 1};
    GetShortPathWithCycle(&maze, entry);
    MazePrint(&maze);
}

int main(){
    Test1();
    Test2();
    Test3();
    Test4();
    Test5();
    return 0;
}

执行效果:

描述

描述

描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值