Лабиринт Traversal печатает все возможные пути C ++ - PullRequest
0 голосов
/ 17 ноября 2018

Это мой первый вопрос о переполнении стека, и он для моей домашней работы.Что мне нужно сделать, так это найти все возможные пути от начала до конца.Что я делаю, так это то, что я вызываю функцию, если она находит '-', а параметры для функции - это индексы, на которых стоит '-'.Текущие параметры помещаются в стек.Прежде чем объяснить дальше, я хочу показать вывод и лабиринт.

Лабиринт

5 6
s - - - - -
- * * * * -
- * * * * - 
- * * * * -
- - - - - e

Первые два int s - это строки и столбцы.

Output

00,01,11,21,22,02,03,13,23,22,04,05,15,25,35,45,44,43,42,32,22

Выходные данные извлекаются из стека.

В некоторой степени выходные данные являются правильными, поскольку вы можете видеть, что функция пересекает каждый путь.Что я не могу сделать, так это отслеживать функции и почему я хочу это делать?Потому что я хочу напечатать все пути от начала (0, 0 в этом случае).Как я могу отслеживать функцию, когда она имеет два пути для прохождения, чтобы я могла распечатать ее из начального индекса?

Ожидаемый результат

00,01,11,21,22
00,01,02,03,13,23,22
00,01,02,03,04,05,15,25,35,45,44,43,42,32,22

Iпредоставлю код также при необходимости.Я редактировал код.Я помещаю индексы (1,0) в стек, как сначала 0, затем 1, и выталкиваю два, а также, чтобы удалить его.Я понимаю, почему мой вывод такой (упомянутый выше), потому что, возьмем пример лабиринта в программе в (0,0), у него есть две опции: идти вверх или вниз.он выходит из строя, и потому что все эти операторы, если нет, если еще программа после выполнения функции проверяет другие условия, она переходит к своей другой опции, которая является правильной.Хорошо, а как насчет вывода?все индексы помещаются в стек, и когда 'e' найден, он печатает все сохраненные индексы, но не удаляет их.для этого примера я могу вытолкнуть все из стека после печати, и выходные данные будут в порядке (не повторяя), возьмите другой пример

Пример

6 6 s 1 1 1 1 1 0 0 1 00 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 1 1 e

В этом примере вы можете видеть, что у него есть два варианта в (0,2), поэтому яне может вытолкнуть все из стека после достижения первого конца пути.потому что это будет поп (0,0) и (0,1), а также.то, что я хочу, это всплывать только до (0,2)

Это то, что я пытаюсь сделать.

#include<iostream>
#include<string.h>
#include<fstream>
using namespace std;
ofstream fout("Q1(output).txt");
ifstream fin("Q1.txt");
class stack
{
    private:
        int row,col;
        int top;
        string str;
        int sourceA,sourceB,destinationA,destinationB;
        char **store;//arr which has maze is passed into class . 'store' has maze.
    public: 
            stack(int row,int col)//constructor , paramerters are rows and cols
        {

            this->row=row;
            this->col=col;
            top=-1;
            sourceA=0;
            sourceB=0;
        }   
    void finish()
    {
        while(top!=-1)
        {
            top--;
        }
    }

    void push(int dataA,int dataB )//push two indexes in str like (0,1) pushed as first 0 then 1 
    {
        if(top==-1)
        {
        top++;
        str[top]=dataA ;
        top++;
        str[top]=dataB  ;
        }
        else
        {
        top++;
        str[top]='1';
        top++;
        str[top]=dataA ;
        top++;
        str[top]=dataB  ;

        }

    }
    void  pop(int varA ,int varB)//This function was made for other purpose but not used 
    {
        for(int a=0;a<top+1;a++)
        {
            if(a==varA && a+1==varB )
            {
                top=a-2;
                cout<<top;
            }
        }

        cout<<endl;
    }
    int ret()
    {
        return top;
    }
    void empty()
    {
        if(top==-1)
        cout<<"\nEmpty\n";
        else 
        cout<<"\nNot Empty\n";
    }
    void get(char **arr)// saving arr(Maze) into store
    {
            char ch;
            store=NULL;
            store=new char*[row];
            for(int a=0;a<row;a++)
            {
                store[a]=new char[col];
                for(int b=0;b<col;b++)
                {

                store[a][b]=arr[a][b];  
                cout<<store[a][b];

                if(arr[a][b]=='s')
                {
                    sourceA=a;//saving the 's' index , my inititate starts from here .
                    sourceB=b;

                }
                else if(arr[a][b]=='e')
                {
                    destinationA=a;//saving the 'e' index , used later.
                    destinationB=b; 
                }
                }
                cout<<endl;         
            }
            }
            int getA()
            {
                return sourceA;
            }
            int getB()
            {
                return sourceB;
            }
            int getAD()
            {
                return destinationA;
            }
            int getBD()
            {
                return destinationB;
            }

            int initiate(int a,int b)
            {
                 int tempA,tempB;
                push(a,b);

                 if(a>0 )
                {

                 if(store[a-1][b]=='1'&&store[a-1][b]!='v')
                {

                    store[a][b]='v';
                    initiate(a-1,b);
                    store[a][b]='1' ;

                }
                }

                 if(b>0 )
                {

                 if(store[a][b-1]=='1'&&store[a][b-1]!='v')
                {

                    store[a][b]='v';
                    initiate(a,b-1);
                    store[a][b]='1' ;


                }
                }

                if(a!=row-1)
                {

                 if(store[a+1][b]=='1'&&store[a+1][b]!='v')
                {

                    store[a][b]='v';
                    initiate(a+1,b);
                    store[a][b]='1' ;

                }
                }

                if(b!=col-1)
                {

                 if(store[a][b+1]=='1'&&store[a][b+1]!='v')
                {

                    store[a][b]='v';                
                    initiate(a,b+1);
                    store[a][b]='1' ;

                }
                }
                 if(a+1==destinationA && b==destinationB ||a-1==destinationA && b==destinationB ||a==destinationA && b+1==destinationB ||a==destinationA && b-1==destinationB )
                {
                    push(destinationA,destinationB);                
                    cout<<"\nPath  : \n";
                    print1();


                }
            pop();

            }
            void print1()
            {
                for(int  a=0;a<top+1;a++)
                {

                    if(str[a]!='1')
                    {
                    int ret=str[a];
                    cout<<ret;
                    fout<<ret;
                    }
                    else
                    {
                        cout<<endl;
                        fout<<endl;                             
                    }
                }

                fout.close();
                }
    int pop()
    {

        int ret=str[top];
        top--;
        int ret1=str[top];
        top--;

    }   
        void show()
        {
            cout<<endl<<endl;
            for(int a=0;a<row;a++)
                {
            for(int b=0;b<col;b++)
                {
                    cout<<store[a][b];

                }
                cout<<endl;
        }
        }

};
main()
{

    char ch;
    int row,col;
    fin >> row;
    fin >> col;
    stack s(row,col);
    char **arr=NULL;
    arr=new char*[row];     
            for(int a=0;a<row;a++)
            {
            arr[a]=new char[col];       
            for(int b=0;b<col;b++)
                {
                fin>>ch;
                arr[a][b]=ch;           
                }

            }

    fin.close();
    s.get(arr);
    s.initiate(s.getA(),s.getB());

    s.show();

    exit(1);
    }

1 Ответ

0 голосов
/ 18 ноября 2018

Печать всех путей может быть выполнена с использованием рекурсии, как вы делаете, но вам нужно будет отслеживать путь, который вы выбрали для достижения цели, и либо распечатывать его при каждом прибытии в пункт назначения, либо сохранять его вконтейнер.Я предпочитаю последний подход.Путь может быть стеком или другой структурой, которая поддерживает операции push / pop.Каждый узел, который вы посещаете в своем обходе, должен быть добавлен к пути и извлечен после того, как все его соседи полностью развернуты.

Вот рекурсивный алгоритм построения пути в псевдокоде:

function DFS(row: int, col: int, maze: char[][], path: int[][], result: int[][][]) {
    path.push([row, col])

    if ([row, col] is the destination) {
        result.add(path)
    }
    else {
        for (direction in each_cardinal_direction) {
            new_row = row + direction.row
            new_col = col + direction.col

            if (in_bounds(new_row) and in_bounds(new_col) and 
                maze[new_row][new_col] is unvisited) {

                maze[row][col] = visited
                DFS(new_row, new_col, maze, path, result)
                maze[row][col] = unvisited
            }
        }
    }

    path.pop()
}

Мне не совсем понятно, почему вы используете как явное, так и неявное состояние;обычно при запуске DFS используют явный стек и цикл while или используют рекурсию и сохраняют все состояния как кадры в стеке вызовов.Подумайте об улучшении четкости имен, дизайна и пробелов / отступов, чтобы легче было следовать вашей логике.

Например, str - это массив, который действует как стек и должен называться так, в то время как ваш класс stack на самом деле вовсе не стек, а скорее решатель лабиринтов.Ваши pop функции не точны и должны удалять только один элемент за один раз.

Кроме того, поскольку вы используете классы и строки C ++, вы также можете использовать преимущества контейнеров.

Вот рекурсивный пример, который временно изменяет лабиринт, добавляя стены, чтобы отметить посещенные узлы, чтобы избежать циклов:

#include <iostream>
#include <vector>

void DFS(
    int row, int col,
    std::vector<std::vector<char>> &maze, 
    std::vector<std::pair<int, int>> &path,
    std::vector<std::vector<std::pair<int, int>>> &result
) {
    path.push_back(std::make_pair(row, col));

    if (maze[row][col] == 'e') {
        result.push_back(path);
    }
    else {
        int dirs[][2] = {{0, -1}, {0, 1}, {1, 0}, {-1, 0}};

        for (auto d : dirs) {
            int r = d[0] + row;
            int c = d[1] + col;

            if (r >= 0 && c >= 0 && r < maze.size() && 
                c < maze[r].size() && maze[r][c] != '*') {
                maze[row][col] = '*';
                DFS(r, c, maze, path, result);
                maze[row][col] = '-';
            }
        }
    }

    path.pop_back();
}

std::vector<std::vector<std::pair<int, int>>> 
getPaths(std::vector<std::vector<char>> maze) {
    std::vector<std::vector<std::pair<int, int>>> result;
    std::vector<std::pair<int, int>> path;
    int row = -1;
    int col = -1;

    for (int i = 0; i < maze.size() && row == -1; i++) {
        for (int j = 0; j < maze[i].size() && col == -1; j++) {
            if (maze[i][j] == 's') {
                row = i;
                col = j;
            }
        }
    }

    DFS(row, col, maze, path, result);
    return result;
}

int main() {
    std::string raw = "s-----\n*-*-*-\n*-e-*-\n**-**-\n**----";
    std::vector<std::vector<char>> maze;
    std::vector<char> row;

    for (int i = 0; i < raw.size(); i++) {
        if (raw[i] == '\n') {
            maze.push_back(row);
            row.clear();
        }
        else {
            row.push_back(raw[i]);
        }
    }

    maze.push_back(row);

    for (auto &path : getPaths(maze)) {
        std::cout << std::endl << '[';

        for (auto &cell : path) {
            std::cout << '(' << cell.first << 
                      "," << cell.second << ')';
        }

        std::cout << ']' << std::endl;
    }
}

Вывод:

[(0,0)(0,1)(0,2)(0,3)(0,4)(0,5)(1,5)(2,5)(3,5)(4,5)(4,4)(4,3)(4,2)(3,2)(2,2)]
[(0,0)(0,1)(0,2)(0,3)(1,3)(2,3)(2,2)]
[(0,0)(0,1)(1,1)(2,1)(2,2)]

Попробуйте!

...