Поиск пути в матрице с++

184
01 января 2022, 11:20

Всем привет :)

Вопрос такой : Имеется матрица вида

4 7
...*...
.......
..###..
...@...

где '@' - шарик ,который нужно переместить в '*'.Символ '#' - стена(через них ходить нельзя),через символ '.' ходить можно. Задача заключается в том чтобы найти количество минимальных путей из @ в *.(например в данном примере кол-во минимальных путей == 6)

Мой алгоритм такой: сначала ищу всевозможные пути и записываю их в **path(путем будет 1,2,3,4,5...*)

После этого с помощью рекурсии иду с конца(с '*') до начала и на каждой итерации рекурсии проверяю есть ли еще какой нибудь путь,если есть то global_count_of_ways++ .

Проблема в том что это очень долго. При больших N(строки) и M(столбцы) вылезает time limit.

Вот код,который я написал

#include <iostream>
#include <queue>
using namespace std;
struct way {
    int visited;
    int count_way;
};
/* нахождение пути*/
void find_road(int n, int m, int row, int col, char** lab, int** visited, way** path, queue<int>& plan) {
    if (!visited[row][col]) {
        /* проверяем не вышли ли мы за границы лабиринта, есть ли клетка
        в массиве посещенных и можно ли через нее пройти*/
        if ((row + 1) < n && (row + 1) >= 0 && !visited[row + 1][col] &&
            (lab[row + 1][col] == '.' || lab[row + 1][col] == '*')) {
            path[row + 1][col].visited = path[row][col].visited + 1;
            path[row + 1][col].count_way += path[row][col].count_way;
            plan.push(row + 1);
            plan.push(col);
        }
        if ((row - 1) < n && (row - 1) >= 0 && !visited[row - 1][col] &&
            (lab[row - 1][col] == '.' || lab[row - 1][col] == '*')) {
            path[row - 1][col].visited = path[row][col].visited + 1;
            path[row - 1][col].count_way += path[row][col].count_way;
            plan.push(row - 1);
            plan.push(col);
        }
        if ((col + 1) < m && (col + 1) >= 0 && !visited[row][col + 1] &&
            (lab[row][col + 1] == '.' || lab[row][col + 1] == '*')) {
            path[row][col + 1].visited = path[row][col].visited + 1;
            path[row][col + 1].count_way += path[row][col].count_way;
            plan.push(row);
            plan.push(col + 1);
        }
        if ((col - 1) < m && (col - 1) >= 0 && !visited[row][col - 1] &&
            (lab[row][col - 1] == '.' || lab[row][col - 1] == '*')) {
            path[row][col - 1].visited = path[row][col].visited + 1;
            path[row][col - 1].count_way += path[row][col].count_way;
            plan.push(row);
            plan.push(col - 1);
        }
        visited[row][col] = 1; /* отмечаем клетку в которой побывали */
    }
}

int main() {
    int n, m, x_start, y_start, x_end, y_end, x, y;
    queue <int> plan;
    cin >> n; cin >> m;
    char** lab = new char*[n];
    int** visited = new int*[n];
    way** path = new way*[n];
    for (int i = 0; i < n; i++) {
        lab[i] = new char[m];   /* массив для хранения лабиринта */
        visited[i] = new int[m]; /* массив для хранения информации о посещении клеток*/
        path[i] = new way[m];  /* массив для хранения найденных путей */
        for (int j = 0; j < m; j++) {
            visited[i][j] = 0;
            path[i][j].visited = -1;
            path[i][j].count_way = 0;
            cin >> lab[i][j];
            if (lab[i][j] == '@') { /* находим начало пути*/
                x_start = i;
                y_start = j;
                plan.push(i);  /* заносим начальную клетку */
                plan.push(j);  /* в план посещения */
                path[i][j].visited = 1;
                path[i][j].count_way = 1;
            }
            else if (lab[i][j] == '*') { /* находим конечную точку */
                x_end = i;
                y_end = j;
            }
        }
    }
    while (!plan.empty()) { /* пока очередь посещения клеток непустая*/
        x = plan.front();
        plan.pop();
        y = plan.front();
        plan.pop();
        find_road(n, m, x, y, lab, visited, path, plan); /* продолжаем поиск пути*/
    }

    cout << path[x_end][y_end].count_way % 1000000007 << endl;
    return 0;
}

Заранее спасибо :)

Answer 1
#include <algorithm>
#include <iostream>
#include <queue>
#include <string>
#include <vector>
#define PATH std::vector<POSITION>
#define QUEUE std::queue<PATH>
int rows;
int cols;
int shortest_path_length;
int shortest_path_counter;
struct POSITION {
    int x;
    int y;
};
bool operator == (POSITION a, POSITION b) {
    return a.x == b.x && a.y == b.y;
}
bool operator != (POSITION a, POSITION b) {
    return a.x != b.x || a.y != b.y;
}
POSITION start {};
POSITION finish {};
void check_position(POSITION verified_position, PATH current_path, QUEUE &paths) {
    if (verified_position.x < 0 || verified_position.x > cols) {
        return;
    }
    if (verified_position.y < 0 || verified_position.y > rows) {
        return;
    }
    if (verified_position == finish) {
        if (current_path.size() == shortest_path_length) {
            shortest_path_counter++;
        } else {
            shortest_path_length = current_path.size();
            shortest_path_counter = 1;
        }
    } else {
        if (std::find(current_path.begin(), current_path.end(), verified_position) == current_path.end()) {
            PATH new_path(current_path);
            new_path.push_back(verified_position);
            paths.push(new_path);
        }
    }
}
int main() {
    std::cin >> rows >> cols;
    bool graph[rows][cols];
    shortest_path_length = rows * cols;
    std::string line;
    for (int row = 0; row < rows; row++) {
        std::cin >> line;
        for (int col = 0; col < cols; col++) {
            if (line[col] == '#') {
                graph[row][col] = false;
                continue;
            }
            if (line[col] == '@') {
                start = { col, row };
            }
            if (line[col] == '*') {
                finish = { col, row };
            }
            graph[row][col] = true;
        }
    }
    QUEUE paths;
    PATH path = { { start } };
    paths.push(path);
    while (!paths.empty()) {
        PATH current_path = paths.front();
        if (current_path.size() > shortest_path_length) {
            paths.pop();
            continue;
        }
        POSITION current_position = current_path.back();
        POSITION next_position { current_position.x - 1, current_position.y };
        if (graph[next_position.y][next_position.x]) {
            check_position(next_position, current_path, paths);
        }
        next_position.x = current_position.x + 1;
        if (graph[next_position.y][next_position.x]) {
            check_position(next_position, current_path, paths);
        }
        next_position.x = current_position.x;
        next_position.y = current_position.y - 1;
        if (graph[next_position.y][next_position.x]) {
            check_position(next_position, current_path, paths);
        }
        next_position.y = current_position.y + 1;
        if (graph[next_position.y][next_position.x]) {
            check_position(next_position, current_path, paths);
        }
        paths.pop();
    }
    std::cout << shortest_path_counter;
    return 0;
}
READ ALSO
О моделях памяти в spinlock mutex

О моделях памяти в spinlock mutex

В книге "Параллельное программирование на С++ в действии" приводится пример спинлока

179
Синхронная прокрутка нескольких listbox winforms c#

Синхронная прокрутка нескольких listbox winforms c#

Есть 4 листбокса в winforms, количество айтемов там всегда одинаковое, как сделать синхронную прокрутку с клавиатуры(стрелок), колесика мышки...

158
Проблема с выводом значения по умолчанию

Проблема с выводом значения по умолчанию

Я написал запрос и он работает верно, но когда дело дошло до добавления значения по умолчанию, я получаю ошибку:

83