using System; using System.Collections.Generic; using System.Linq; namespace HJ43 { internal class Program { public class Point { public int X { get; set; } public int Y { get; set; } public Point Father { get; set; } public Point() { } public Point(int x, int y) { X = x; Y = y; } public Point(int x, int y, Point point) { X = x; Y = y; Father = point; } public override string ToString() { return $"({X},{Y})"; } } static void Main(string[] args) { var inputStr = Console.ReadLine(); var stringArr = inputStr.Split(); int m = int.Parse(stringArr[0]); int n = int.Parse(stringArr[1]); int[,] ints = new int[m, n]; for (int i = 0; i < m; i++) { var strs = Console.ReadLine().Split(); for (int j = 0; j < n; j++) { ints[i, j] = int.Parse(strs[j]); } } bool[,] isVisited = new bool[m, n]; List<Point> path = new List<Point>(); //if (DeepthFirstSearch(ints, isVisited, 0, 0, path)) //{ // foreach (Point p in path) // { // Console.WriteLine(p); // } //} Point finalPoint = BreadthFirstSearch(ints, isVisited, 0, 0, path); if (finalPoint != null) { List<Point> points = new List<Point>(); points.Add(finalPoint); Point father = finalPoint.Father; while (true) { if (father == null) { break; } //从终点往起点方向加入路径点 points.Add(father); father = father.Father; } //回为加入时是从终点加入,因此需要倒置输出 points.Reverse(); foreach (Point point in points) { Console.WriteLine(point); } } } /// <summary> /// 深度优先搜索,从一个点一直往下层走,不断往树的叶的方向走 /// </summary> static bool DeepthFirstSearch(int[,] map, bool[,] isVisited, int x, int y, List<Point> path) { path.Add(new Point(x, y)); while (true) { if (x == map.GetLength(0) - 1 && y == map.GetLength(1) - 1) { return true; } //假如向下能走并且下边的点没有被访问过,向下走 if (x + 1 < map.GetLength(0) && map[x + 1, y] == 0 && isVisited[x + 1, y] == false) { x = x + 1; path.Add(new Point(x, y)); //从这个点开始下一步搜索,同时将这个点标记为访问过,防止下个点搜索后回到这个点 isVisited[x, y] = true; continue; } //假如向右能走并且右边的点没有被访问过,向右走 if (y + 1 < map.GetLength(1) && map[x, y + 1] == 0 && isVisited[x, y + 1] == false) { y = y + 1; path.Add(new Point(x, y)); //从这个点开始下一步搜索,同时将这个点标记为访问过,防止下个点搜索后回到这个点 isVisited[x, y] = true; continue; } //假如向上能走并且上边的点没有被访问过,向上走 if (x - 1 >= 0 && map[x - 1, y] == 0 && isVisited[x - 1, y] == false) { x = x - 1; path.Add(new Point(x, y)); //从这个点开始下一步搜索,同时将这个点标记为访问过,防止下个点搜索后回到这个点 isVisited[x, y] = true; continue; } //假如向左能走并且左边的点没有被访问过,向左走 if (y - 1 >= 0 && map[x, y - 1] == 0 && isVisited[x, y - 1] == false) { y = y - 1; path.Add(new Point(x, y)); //从这个点开始下一步搜索,同时将这个点标记为访问过,防止下个点搜索后回到这个点 isVisited[x, y] = true; continue; } //上下左右都不能走时,回退一步, //由于之前这条路径上的点都被标记访问过,因此不会再走这条路径 path.RemoveAt(path.Count - 1); //如果多次深入搜索之后都没有路径,且最后回退到起始点,说明没用路径; if (path.Count == 1) { return false; } x = path.Last().X; y = path.Last().Y; } } /// <summary> /// 广度优先搜索,从树的一层层去搜索,搜索完成一层再下一层 /// </summary> static Point BreadthFirstSearch(int[,] map, bool[,] isVisited, int x, int y, List<Point> path) { path.Add(new Point(x, y)); Point p = null; while (true) { //无解,退出 if (path.Count == 0) { return null; } p = path[0]; path.RemoveAt(0); x = p.X; y = p.Y; if (x == map.GetLength(0) - 1 && y == map.GetLength(1) - 1) { return p; } //假如向下能走并且下边的点没有被访问过,加入进来 if (x + 1 < map.GetLength(0) && map[x + 1, y] == 0 && isVisited[x + 1, y] == false) { path.Add(new Point(x + 1, y, p)); //将这个点标记为访问过,防止下个点搜索后再次加入这个点,保证每个点只被加入一次 isVisited[x + 1, y] = true; } //假如向右能走并且右边的点没有被访问过,加入进来 if (y + 1 < map.GetLength(1) && map[x, y + 1] == 0 && isVisited[x, y + 1] == false) { path.Add(new Point(x, y + 1, p)); //将这个点标记为访问过,防止下个点搜索后再次加入这个点,保证每个点只被加入一次 isVisited[x, y + 1] = true; } //假如向上能走并且上边的点没有被访问过,加入进来 if (x - 1 >= 0 && map[x - 1, y] == 0 && isVisited[x - 1, y] == false) { path.Add(new Point(x - 1, y, p)); //将这个点标记为访问过,防止下个点搜索后再次加入这个点,保证每个点只被加入一次 isVisited[x - 1, y] = true; } //假如向左能走并且左边的点没有被访问过,加入进来 if (y - 1 >= 0 && map[x, y - 1] == 0 && isVisited[x, y - 1] == false) { path.Add(new Point(x, y - 1, p)); //将这个点标记为访问过,防止下个点搜索后再次加入这个点,保证每个点只被加入一次 isVisited[x, y - 1] = true; } } } } }