牛客HJ43迷宫问题 - 创建智能体通过策略自己找路

问题描述

描述

定义一个二维数组 N*M ,如 5 × 5 数组下所示:

int maze[5][5] = {
0, 1, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
};

它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的路线。入口点为[0,0],既第一格是可以走的路。

数据范围: 2≤n,m≤10 2≤n,m≤10 , 输入的内容只包含 0≤val≤1 0≤val≤1
输入描述:

输入两个整数,分别表示二维数组的行数,列数。再输入相应的数组,其中的1表示墙壁,0表示可以走的路。数据保证有唯一解,不考虑有多解的情况,即迷宫只有一条通道。
输出描述:

左上角到右下角的最短路径,格式如样例所示。
示例1
输入:

5 5
0 1 0 0 0
0 1 1 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0

输出:

(0,0)
(1,0)
(2,0)
(2,1)
(2,2)
(2,3)
(2,4)
(3,4)
(4,4)

思路

  • 前进策略: 一直靠着左侧的墙壁走
  • 假设初始方向为col的方向
  • 如果能向左走,直接向左转弯,并向前走一步;
  • 否则依次尝试:向前走、向右走。注意:
    • 向前走时不需要修改当前的前进方向
    • 尝试向右走时,无论是否能够向右走出一步,都直接向右转方向,这样连续转几次,就能转出死角
  • 当 当前位置 等于 出口位置时结束
  • 通过删除重复不必要的足迹使路径最短——已知了只有一条通路

代码C++

在这里插入图片描述

#include <iostream>
#include <string>
#include <vector>

using namespace std;

struct Pos {
    int col;
    int row;

    bool operator==(const Pos& another) const {
        return another.col == col && another.row == row;
    }
};

class Agent {
public:
    int N;  // 总行数
    int M;  // 总列数
    vector<vector<int>> data;  // 迷宫矩阵

    int direction;
    vector<Pos> path;
    Pos cur_pos;
    Pos final_pos;

public:
    void get_input() {
        cin >> N >> M;
        data = vector<vector<int>>(N, vector<int>(M));

        for (int i=0; i<N; ++i) {
            for (int j=0; j<M; ++j) {
                cin >> data[i][j];
            }
        }

        final_pos.row = N - 1;
        final_pos.col = M - 1;

        cur_pos.row = 0;
        cur_pos.col = 0;
        path.push_back(cur_pos);
        direction = 1;
    }

    void print_path() {
        for (auto& pos : path) {
            printf("(%d,%d)\n", pos.row, pos.col);
        }
    }

    bool valid_pos(const Pos& pos) {
        if (pos.col >= 0 && pos.col < M &&
            pos.row >= 0 && pos.row < N &&
            data[pos.row][pos.col] == 0) 
        {
            return true;
        } else {
            return false;
        }

    }
    
    bool move_forward() {
        Pos next_pos = cur_pos;
        if (direction == 1) {
            next_pos.col += 1;
        } else if (direction == 2) {
            next_pos.row += 1;
        } else if (direction == 3) {
            next_pos.col -= 1;
        } else {
            next_pos.row -= 1;
        }
        // printf("forwd: %d,%d\n", next_pos.row, next_pos.col);

        if (valid_pos(next_pos)) {
            cur_pos = next_pos;
            path.push_back(next_pos);
            return true;
        } else {
            return false;
        }
    }

    bool move_right() {
        Pos next_pos = cur_pos;
        if (direction == 1) {
            next_pos.row += 1;
        } else if (direction == 2) {
            next_pos.col -= 1;
        } else if (direction == 3) {
            next_pos.row -= 1;
        } else {
            next_pos.col += 1;
        }
        // printf("right: %d,%d\n", next_pos.row, next_pos.col);

        direction = (direction + 1) <= 4 ? (direction + 1) : 1;  // 更新方向
        if (valid_pos(next_pos)) {
            cur_pos = next_pos;
            path.push_back(next_pos);
            return true;
        } else {
            return false;
        }
    }

    bool move_left() {
        Pos next_pos = cur_pos;
        if (direction == 1) {
            next_pos.row -= 1;
        } else if (direction == 2) {
            next_pos.col += 1;
        } else if (direction == 3) {
            next_pos.row += 1;
        } else {
            next_pos.col -= 1;
        }
        // printf("left : %d,%d\n", next_pos.row, next_pos.col);

        if (valid_pos(next_pos)) {
            cur_pos = next_pos;
            direction = (direction - 1) >= 1 ? (direction - 1) : 4;  // 更新方向
            path.push_back(next_pos);
            return true;
        } else {
            return false;
        }
    }


    // 前进策略: 一直靠着左侧的墙壁走
    void find_way() {
        while (true) {
            if (cur_pos == final_pos) {
                break;
            }

            // 根据 当前 direction 判断前后左右
            if (move_left()) {       /*左侧是墙壁*/
                trim_path();
                // printf("向左走\n");
            } else {
                if (move_forward()) {   /*前面能走*/
                    trim_path();
                    // printf("向前走\n");
                } else {
                    /*向右能走,注意无论是否能向右走,都直接向右转向了,所以一定能转出去*/
                    if (move_right()) {
                        trim_path();
                        // printf("向右走\n");
                    }
                }
            }

        }
    }

    // 移除不必要的足迹: A-B-D-E-B-C-X-Y-Z,   B-D-E就是不必要的足迹,  不能有重复的坐标点
    void trim_path() {
        Pos end = path.back();

        for (auto iter = path.begin(); iter != path.end()-1; iter++) {
            if (*iter == end) {
                for (auto iter2 = iter; iter2 != path.end()-1; iter2) {
                    path.erase(iter2);
                }
                break;
            }
        }
    }
};


int main()
{
    Agent agent;
    agent.get_input();

    agent.find_way();

    agent.print_path();
    
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值