using System; using System.Collections.Generic; class Program { static void Main() { var input = Console.ReadLine().Split(); int H = int.Parse(input[0]); int W = int.Parse(input[1]); var grid = new char[H][]; for (int i = 0; i < H; i++) grid[i] = Console.ReadLine().ToCharArray(); // 移動方向(上、下、左、右) int[] dr = { -1, 1, 0, 0 }; int[] dc = { 0, 0, -1, 1 }; // (左右移動回数, 上下移動回数) の最小値を保存 var dist = new (int X, int Y)[H, W]; const int INF = int.MaxValue; for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) dist[i, j] = (INF, INF); // 優先度付きキュー: (左右移動回数, 上下移動回数, 行, 列) var pq = new PriorityQueue<(int X, int Y, int r, int c), (int X, int Y)>(); dist[0, 0] = (0, 0); pq.Enqueue((0, 0, 0, 0), (0, 0)); while (pq.Count > 0) { var (x, y, r, c) = pq.Dequeue(); if ((x, y) != dist[r, c]) continue; // 古い情報はスキップ for (int d = 0; d < 4; d++) { int nr = r + dr[d]; int nc = c + dc[d]; if (nr < 0 || nr >= H || nc < 0 || nc >= W) continue; if (grid[nr][nc] == '#') continue; int nx = x + (d >= 2 ? 1 : 0); // 左右移動なら X++ int ny = y + (d < 2 ? 1 : 0); // 上下移動なら Y++ var newCost = (nx, ny); if (Compare(newCost, dist[nr, nc]) < 0) { dist[nr, nc] = newCost; pq.Enqueue((nx, ny, nr, nc), newCost); } } } var goal = dist[H - 1, W - 1]; if (goal.X == INF) { Console.WriteLine("No"); } else { Console.WriteLine("Yes"); Console.WriteLine($"{goal.X} {goal.Y}"); } } // (X, Y) の辞書順比較: Xが小さい方が優先。同じならYが小さい方。 static int Compare((int X, int Y) a, (int X, int Y) b) { if (a.X != b.X) return a.X < b.X ? -1 : 1; if (a.Y != b.Y) return a.Y < b.Y ? -1 : (a.Y > b.Y ? 1 : 0); return 0; } }