• Feed
  • Explore
  • Ranking
/
/
    CodingTest

    코딩테스트 준비 - 나이트의 이동

    혼자서 다시푸는 코딩테스트 준비 일지 - 25
    BFS그래프 이론
    B
    Brocolling
    2024.09.24
    ·
    5 min read

    다시푸는 코딩 테스트 준비 일지

    • 응시 사이트 : BOJ

    • 문제 : 7562.나이트의 이동

    • 사용언어 : C#

    • 난이도 : 중하

    • 풀이시간 : 53m

    • 유형 : BFS, 그래프 이론

    문제

    체스판 위에 한 나이트가 놓여져 있다. 나이트가 한 번에 이동할 수 있는 칸은 아래 그림에 나와있다. 나이트가 이동하려고 하는 칸이 주어진다. 나이트는 몇 번 움직이면 이 칸으로 이동할 수 있을까?

    until-1489

    입력

    입력의 첫째 줄에는 테스트 케이스의 개수가 주어진다.

    각 테스트 케이스는 세 줄로 이루어져 있다. 첫째 줄에는 체스판의 한 변의 길이 l(4 ≤ l ≤ 300)이 주어진다. 체스판의 크기는 l × l이다. 체스판의 각 칸은 두 수의 쌍 {0, ..., l-1} × {0, ..., l-1}로 나타낼 수 있다. 둘째 줄과 셋째 줄에는 나이트가 현재 있는 칸, 나이트가 이동하려고 하는 칸이 주어진다.

    출력

    각 테스트 케이스마다 나이트가 최소 몇 번만에 이동할 수 있는지 출력한다.

    예제 입력 1 복사

    3
    8
    0 0
    7 0
    100
    0 0
    30 50
    10
    1 1
    1 1
    

    예제 출력 1 복사

    5
    28
    0
    

    문제 풀이 접근

    이 문제의 요구사항은 나이트는 이동할 수 있으며, 시작점이 주어지고, 그 지점에서 도착점을 갈 수 있는지, 간다고한다면, 최소 몇번의 이동을 통해서 갈 수 있는지 출력하는 것이다.

    먼저 나이트의 이동 방향을 알아야한다. 첨부된 사진처럼 상하 각각 2칸, 좌우 1칸 움직일 수 있는 것이 나이트의 이동 규칙이다.

    이 문제의 방법론은 아래와 같다.
    1. 나이트의 이동방법은 총 8가지
    2. 상하좌우 한번씩 탐색하던 로직을 나이트의 이동규칙 8가지로 변경해서 탐색하도록 한다.
    3. 이동한 횟수를 넣기위해 현재 map[NewPosX,NewPosY] = map[CurPosX,CurPosY] +1 을 한다.

    정답 작성 코드 (C#)

    using System;
    using System.Collections.Generic;
    using System.IO.Pipes;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Security.Cryptography.X509Certificates;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Test
    {
        internal class Program
        {
            static void Main(string[] args)
            {
                Solution solution = new Solution();
                solution.solve();
            }
        }
    
    
        public class Solution
        {
            public int mapLength;
            public bool[,] isVisited;
            public int[,] maps;
            public int knightPosX;
            public int knightPosY;
    
            public int goalPosX;
            public int goalPosY;
    
            public int[] dx = new int[8] {2,1,-1,-2,-2,-1,1,2};
            public int[] dy = new int[8] {1,2,2,1,-1,-2,-2,-1};
    
            /*
     * TC 는 3줄 
     * 첫줄 : 체스판 한변의 길이 4 <= a <= 300
     * 크기 : a * a
     * 
     * 체스판은 두 수의 쌍({0,0} ~ {(a-1),(a-1)}) 으로 나타낼 수 있음
     * 
     * 둘째줄 : 나이트의 현재 칸
     * 
     * 셋째줄 : 나이트가 이동하려고 하는 칸
     * 
     */
    
            public void solve()
            {
                int tc = Int32.Parse(Console.ReadLine());
                mapLength = 0;
    
                for (int i= 0; i < tc; ++i)
                {
                    mapLength = Int32.Parse(Console.ReadLine());
                    Init(mapLength);
    
                    string[] curPos = Console.ReadLine().Split(' ');
                    knightPosX = Int32.Parse(curPos[0]);
                    knightPosY = Int32.Parse(curPos[1]);
    
                    string[] goalPos = Console.ReadLine().Split(' ');
                    goalPosX = Int32.Parse(goalPos[0]);
                    goalPosY = Int32.Parse(goalPos[1]);
    
                    BFS();
                    Console.WriteLine(maps[goalPosX, goalPosY]);
                }
            }
    
            public void Init(int tc)
            {
                isVisited = new bool[tc, tc];
                maps = new int[tc, tc];
    
                knightPosX = 0;
                knightPosY = 0;
                goalPosX = 0;
                goalPosY = 0;
            }
    
            public void BFS()
            {
                Queue<Tuple<int,int>>  q = new Queue<Tuple<int, int>>(); 
    
                q.Enqueue(new Tuple<int,int>(knightPosX,knightPosY));
    
                while(q.Count > 0)
                {
                    var pos = q.Dequeue();
    
                    if (isVisited[pos.Item1, pos.Item2] == true)
                        continue;
    
                    isVisited[pos.Item1, pos.Item2] = true;
    
                    if (pos.Item1 == goalPosX && pos.Item2 == goalPosY)
                        break;
                    // 목적지 도착 시
    
                    for(int i = 0; i < 8; ++i)
                    {
                        var newPosX = pos.Item1 + dx[i];
                        var newPosY = pos.Item2 + dy[i];
    
                        if (isCheckSection(newPosX, newPosY) == false)
                            continue;   
    
                        if (isVisited[newPosX, newPosY] == true)
                            continue;
    
                        maps[newPosX,newPosY] = maps[pos.Item1, pos.Item2] + 1;
                        q.Enqueue(new Tuple<int, int>(newPosX, newPosY));
                    }
                }
            }
    
            public bool isCheckSection(int newPosX, int newPosY)
            {
                if (newPosX < 0 || newPosY < 0 || newPosX > mapLength - 1 || newPosY > mapLength - 1)
                    return false;
    
                return true;
            }
        }
    }
    
    
    

    코드 결과

    until-1490






    - 컬렉션 아티클