文章目录
- 问题描述
- 思路
- 代码C++
 
问题描述
描述
定义一个二维数组 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;
}


















