使用递归DFS在迷宫中打印所有可能的路径

时间:2016-08-11 18:48:46

标签: c# algorithm recursion depth-first-search

这是任务:给你一个迷宫,它由N×N个正方形组成,每个都可以通过或不通过。可通过的细胞由" a"之间的较低拉丁字母组成。和" z",以及不可通过 - '#'。其中一个广场是杰克。它标有" *"。

如果他们有共同的墙,则两个正方形是邻居。一步,杰克可以从一个可通行的广场转移到相邻的可通行广场。当杰克穿过可通行的方格时,他写下了每个方格的字母。在每个出口他都会得到一个字。编写一个程序,从给定的迷宫中打印出杰克从所有可能的出口中获取的单词。 输入数据从名为Labyrinth.in的文本文件中读取。在文件的第一行有数字N(2 文件中

输入:

6
a##km#
z#ada#
a*m###
#d####
rifid#
#d#d#t

到目前为止,我已经做到了:

using System;
using System.IO;
using System.Collections.Generic;
using System.Text;

public class Maze
{
    private const string InputFileName = "Labyrinth.in";
    private const string OutputFileName = "Labyrinth.out";
    StringBuilder path = new StringBuilder();

    public class Cell
    {
        public int Row { get; set; }
        public int Column { get; set; }

        public Cell(int row, int column)
        {
            this.Row = row;
            this.Column = column;
        }
    }

    private char[,] maze;
    private int size;
    private Cell startCell = null;

    public void ReadFromFile(string fileName)
    {
        using (StreamReader reader = new StreamReader(fileName))
        {
            // Read maze size and create maze
            this.size = int.Parse(reader.ReadLine());
            this.maze = new char[this.size, this.size];

            // Read the maze cells from the file
            for (int row = 0; row < this.size; row++)
            {
                string line = reader.ReadLine();
                for (int col = 0; col < this.size; col++)
                {
                    this.maze[row, col] = line[col];
                    if (line[col] == '*')
                    {
                        this.startCell = new Cell(row, col);
                    }
                }
            }
        }
    }

    public void FindAllPathsAndPrintThem()
    {
        if (this.startCell == null)
        {
            // Start cell is missing -> no path
            SaveResult(OutputFileName, "");
            return;
        }

        VisitCell(this.startCell.Row,
            this.startCell.Column, path);

        if (path.Length == 0)
        {
            // We didn't reach any cell at the maze border -> no path
            SaveResult(OutputFileName, "");
            return;
        }
    }

    private void VisitCell(int row, int column, StringBuilder path)
    {
        if (row < 0 || row > maze.GetLength(0) - 1 ||
            column < 0 || column > maze.GetLength(1) - 1)
        {
            SaveResult(OutputFileName, path.ToString());
            return;
        }

        if (this.maze[row, column] != 'x' && this.maze[row, column] != '#')
        {
            // The cell is free --> visit it
            if (this.maze[row, column] != '*')
            {
                path.Append(this.maze[row, column]);
                this.maze[row, column] = 'x';
            }
            VisitCell(row, column + 1, path);
            VisitCell(row, column - 1, path);
            VisitCell(row + 1, column, path);
            VisitCell(row - 1, column, path);
        }
    }

    public void SaveResult(string fileName, string result)
    {
        using (StreamWriter writer = new StreamWriter(fileName))
        {
            writer.WriteLine(result);
        }
    }

    static void Main()
    {
        Maze maze = new Maze();
        maze.ReadFromFile(InputFileName);
        maze.FindAllPathsAndPrintThem();
    }
}

很抱歉。需要一个小虫子,但我不知道它在哪里。 输出是madifiddrdzaadamk。提前谢谢。

2 个答案:

答案 0 :(得分:0)

这是我提出的解决方案。它记录了一次通过迷宫时访问过的细胞,但不是所有的尝试。这可以通过使函数返回IEnumerable<string>来完成,该private static IEnumerable<string> VisitCell(int row, int column, bool[,] visited) { if (row < 0 || column < 0 || row >= maze.GetLength(0) || column >= maze.GetLength(1)) yield break; if (maze[row, column] == '#' || visited[row, column]) yield break; if (row == 0 || row == maze.GetLength(0) - 1 || column == 0 || column == maze.GetLength(1) - 1) { yield return maze[row, column].ToString(); } visited[row, column] = true; foreach (var path in VisitCell(row, column + 1, visited)) { yield return maze[row, column] + path; } foreach(var path in VisitCell(row, column - 1, visited)) { yield return maze[row, column] + path; } foreach (var path in VisitCell(row + 1, column, visited)) { yield return maze[row, column] + path; } foreach (var path in VisitCell(row - 1, column, visited)) { yield return maze[row, column] + path; } visited[row, column] = false; } 将表示从迷宫中当前点退出的路径。首先检查你是否离开了迷宫的边缘并且什么也没有返回。然后检查你是否在墙上,如果没有,则不返回路径。否则,检查是否处于边缘,如果是,则返回仅由当前单元格表示的路径。然后,您必须将当前单元格标记为已访问,然后尝试查找4个方向中的每个方向上的所有路径,并将当前单元格连接到您找到的任何单元格并生成它们。然后在结束时将单元格标记为未访问,以便可以用于其他尝试。

private static char[,] maze =
{
    { 'a', '#', '#', 'k', 'm', '#' },
    { 'z', '#', 'a', 'd', 'a', '#' },
    { 'a', '*', 'm', '#', '#', '#' },
    { '#', 'd', '#', '#', '#', '#' },
    { 'r', 'i', 'f', 'i', 'd', '#' },
    { '#', 'd', '#', 'd', '#', 't' }
};

private static void Main(string[] args)
{
    foreach(var path in VisitCell(2, 1, new bool[6, 6]))
        Console.WriteLine(path);
}

然后你可以运行这段代码

{{1}}

获得此结果

  

*女士

     

* madamk

     

* madk

     

* madkm

     

*一个

     

* AZ

     

*氮杂

     

* difid

     

* DIR

     

*确实

您可以调整它以从每条路径的开头删除星号。

答案 1 :(得分:0)

这是正确的代码:

using System;
using System.IO;
using System.Collections.Generic;
using System.Text;

public class Maze
{
    private const string InputFileName = "Labyrinth.in";
    private const string OutputFileName = "Labyrinth.out";

    public class Cell
    {
        public int Row { get; set; }
        public int Column { get; set; }

        public Cell(int row, int column)
        {
            this.Row = row;
            this.Column = column;
        }
    }

    private char[,] maze;
    private int size;
    private Cell startCell = null;

    public void ReadFromFile(string fileName)
    {
        using (StreamReader reader = new StreamReader(fileName))
        {
            // Read maze size and create maze
            this.size = int.Parse(reader.ReadLine());
            this.maze = new char[this.size, this.size];

            // Read the maze cells from the file
            for (int row = 0; row < this.size; row++)
            {
                string line = reader.ReadLine();
                for (int col = 0; col < this.size; col++)
                {
                    this.maze[row, col] = line[col];
                    if (line[col] == '*')
                    {
                        this.startCell = new Cell(row, col);
                    }
                }
            }
        }
    }

    public void FindAllPathsAndPrintThem()
    {
        if (this.startCell == null)
        {
            // Start cell is missing -> no path
            SaveResult(OutputFileName, "");
            return;
        }

        VisitCell(this.startCell.Row,
            this.startCell.Column, "");
    }

    private void VisitCell(int row, int column, string path)
    {
        if (row < 0 || column < 0 || row >= maze.GetLength(0) || column >= maze.GetLength(1))
        {
            return;
        }
        if (row < 0 || row > maze.GetLength(0) - 1 ||
            column < 0 || column > maze.GetLength(1) - 1)
        {
            SaveResult(OutputFileName, path);
            return;
        }

        if (this.maze[row, column] != '#')
        {
            // The cell is free --> visit it
            char x = this.maze[row, column];
            this.maze[row, column] = '#';
            VisitCell(row, column + 1, path + x);
            VisitCell(row, column - 1, path + x);
            VisitCell(row + 1, column, path + x);
            VisitCell(row - 1, column, path + x);
            this.maze[row, column] = x;
        }
    }

    public void SaveResult(string fileName, string result)
    {
        using (StreamWriter writer = new StreamWriter(fileName, true))
        {
            writer.WriteLine(result);
        }
    }

    static void Main()
    {
        Maze maze = new Maze();
        maze.ReadFromFile(InputFileName);
        maze.FindAllPathsAndPrintThem();
    }
}

关于我正在修改字符串的问题的评论,所以现在它可以工作,字符串不会在进程中修改。