【数据结构】------多通路带环迷宫求最短路径(C语言)

本文介绍了一种求解带环多通路迷宫最短路径的方法,通过标记走过的步数而非简单的可达性来避免环路,实现了有效的路径搜索。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

思路:在解决之前的函数时,我们判断函数是否可以落脚,标记可落脚的函数都是通用的,而现在由于迷宫的通路是带环的,如果我们在使用上面提到的不带环的多通路求最短路径的方法,肯定这种结果是错误的,所以对于带环的迷宫求解我们再也不能像以前简单的标记为2,我们应该标记的是走过的步数,这样我们判断是否能落脚时,可以直接判断下一步的步数是否比我们即将标记的步数大,如果大的话,就继续进行落脚标记,否则就不可以。

1) 判断当前点是否能落脚,不能落脚就直接返回
2)能落脚就标记当前点,并且将当前点插入到cur_path中
3) 判定当前点是否为出口,是出口就说明找到了一条路
4) 将这条路与最短路径进行比较,把比较短的路径保存到最短路径当中
5) 不管当前路径是否为最短路径都要进行回溯,回溯到前一个点继续进行查找其他的路径
6)如果不是出口,就探测相邻的4个点,(采用顺时针的方法进行回溯)每探测一个点就调用函数本身,重复1~6的动作。
7)如果我们的四个方向都进行探测过了,就可以进行出栈了(cur_path,short_path的栈顶元素进行出栈)回溯到上一个点

代码的实现:


/////////////////////////////////////////////////////////
/////////////////带环多通路最短路径//////////////////////
/////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////


void MazeInitCycle(Maze *maze)
{
    int map[ROW][COL] =
    {
        { 0, 1, 0, 0, 0, 0 },
        { 0, 1, 1, 1, 0, 0 },
        { 1, 1, 0, 1, 0, 0 },
        { 0, 1, 1, 1, 1, 1 },
        { 0, 1, 0, 0, 0, 0 },
        { 0, 1, 0, 0, 0, 0 }
    };
    int i = 0;
    for (; i < ROW; i++)
    {
        int j = 0;
        for (; j < COL; j++)
        {
            maze->map[i][j] = map[i][j];
        }
    }
}
//判断是否能落脚的函数
int CanStayWithCycle(Maze *maze, Point cur, Point pre)
{
    //在地图外的点都不能落脚
    if (cur.row < 0 || cur.row >= ROW || cur.col < 0 || cur.col >= COL)
    {
        return 0;
    }
    //在地图内的点,且值为1就能直接落脚
    int cur_value = maze->map[cur.row][cur.col];
    int pre_value = maze->map[pre.row][pre.col];
    if (cur_value == 1)
    {
        return 1;
    }
    //当前点如果已经走过了,比较cur对应的值和pre对应的值
    //cur-value = 7,pre-value = 5应该落脚
    //cur-value = 6,pre-value = 5不应该落脚
    //cur-value = 5,pre-value = 5不应该落脚
    //cur-value = 4,pre-value = 5不应该落脚

    //cur-value > pre-value+1就应该落脚
    if (cur_value > pre_value + 1)
    {
        return 1;
    }
    return 0;
}
//标记函数
void MarkWithCycle(Maze *maze, Point cur, Point pre)
{
    if (pre.row == -1 && pre.col == -1)
    {
        //针对入口点进行标记,此时的pre是一个非法点
        //不能根据pre_value+1的方法进行标记
        //由于地图中我们用1表示路,所以这里对于入口点直接标记为2,所以对于后面的标记的数字的意义就是对该数字-1就是从入口点走到该点的所需的步数
        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 GetCycleShort(Maze *maze, Point cur, Point pre, Point entry, SeqStack *cur_path, SeqStack *short_path)
{
    if (maze == NULL || cur_path == NULL || short_path == NULL)
    {
        return;
    }
    //判断当前点是否能落脚(判定规则改变了)
    if (!CanStayWithCycle(maze, cur, pre))
    {
        //不能落脚就直接返回
        return;
    }
    //能落脚就把当前点标记(标记规则也改变了)并且入cur_path栈,cur_path栈保存着我们走过的路径
    MarkWithCycle(maze, cur, pre);
    SeqStackPush(cur_path, cur);
    //更新pre的值,后续判断是否可以落脚标记
    pre = cur;
    //判定当前点是否为出口
    if (IsExit(maze, cur, entry))
    {
        //是出口说明找到了一条路
        printf("找到了一条路\n");
        //将cur_path与short_path进行比较
        if (short_path->size == 0 || cur_path->size < short_path->size)
        {
            printf("找到了一条比较短的路\n");
            //把比较短的路径保存到short_path栈中
            SeqStackAssgin(cur_path, short_path);
        }
        //不管当前的路径是否为最短的路径都要进行回溯,回到前一个点继续找其他的路径
        SeqStackPop(cur_path);
        return;
    }
    //如果不是出口,以当前点为基准点,探测相邻的四个点
    Point up = cur;
    up.row--;
    GetCycleShort(maze, up, pre, entry, cur_path, short_path);

    Point right = cur;
    right.col++;
    GetCycleShort(maze, right, pre, entry, cur_path, short_path);

    Point down = cur;
    down.row++;
    GetCycleShort(maze, down, pre, entry, cur_path, short_path);

    Point left = cur;
    left.col--;
    GetCycleShort(maze, left, pre, entry, cur_path, short_path);

    //如果四个方向都探测过了,就出栈回溯
    SeqStackPop(cur_path);
    return;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值