본문 바로가기
Baekjoon/[5] DFS & BFS

[백준] 7562번 나이트의 이동 JAVA (자바) 풀이

by Poorm 푸름 2023. 9. 17.

문제 7562번 (bfs)

 :  나이트는 몇 번 움직이면 칸으로 이동할 수 있을까?

 
 
 

 [입력]


 :  첫째 줄에는 테스트 케이스 묶음 개수 

 :  테스트 케이스 한묶음 당 3개의 줄이 있다

 :  첫째 줄에는 체스판의 한 변의 길이 (크기 1 × 1)

 :  둘째 줄에는 나이트가 현재있는 칸 위치

 :  셋째 줄에는 나이트가 이동하려는 칸 위치

 

 

 [출력]


 :  각 테스트 케이스 묶음마다 나이트의 최소 이동 횟수 출력

 

 

 [설명]

 

 BFS 

 

 

 현재 정점에 연결된 가까운 점들부터 탐색

 

 Queue를 사용해서 구현

 

 

 

 

 java.awt.Point 

 

-  Point 클래스는 좌표 상의 위치를 나타내는데 사용

-  x와 y좌표값을 저장하기 위한 멤버변수를 갖는다

 

Field Summary
Modifier and Type Field and Description 설명
int x x좌표
int y y좌표
메소드 설명
void setLocation(int x, int y) x, y좌표의 위치값을 설정
Point getLocation() 현재 위치의 x, y좌표값을 반환

출처 : https://codedragon.tistory.com/6044

 

 

 [문제 과정]

 

 

  X Y
좌표  1
 2
 2
 1
- 1 
- 2 
- 2 
- 1 
- 2 
- 1 
 1
 2
 2
 1
- 1 
- 2 
방향 8 가지

    출처 : https://yurimac.tistory.com/47

 

 

위 그림은 체스가 움직일 수 있는 방향을 표현한 것이다
실제로 체스판이나 체스가 저모양 그대로 고정되어 있지 않다는 점 주의하기

 

 

 [코드1]

import java.io.*;
import java.awt.*;
import java.util.*;
public class Main{
    static int T,size,x,y,x1,y1;
    static int arr[][];
    static boolean visit[][];
    static int result=0;
    static int dx[] = {1, 2, 2, 1, -1, -2, -2, -1 };
    static int dy[] = {-2, -1, 1, 2, 2, 1, -1, -2 };
    static Queue<Point> q = new LinkedList<>();
    public static void main(String[] args)throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
 
        T=Integer.parseInt(br.readLine());
       
   
       while(T-->0){
            size=Integer.parseInt(br.readLine());
            arr=new int[size][size];
            visit= new boolean[size][size];
            st= new StringTokenizer(br.readLine());
            x=Integer.parseInt(st.nextToken());
            y=Integer.parseInt(st.nextToken());
            
            st= new StringTokenizer(br.readLine());
            x1=Integer.parseInt(st.nextToken());
            y1=Integer.parseInt(st.nextToken());
            
            bfs();
             System.out.println(arr[x1][y1]); 
        } 
    }
    
    static void bfs(){
        q.add(new Point(x,y));
        visit[x][y]= true;
        
        while(!q.isEmpty()){
            Point p = q.poll();
            
            for(int i =0; i<8;i++){
                int nx = p.x+dx[i];
                int ny = p.y+dy[i];
                
                if(nx>=0 && ny>=0 && nx < size && ny <size){
                    if(!visit[nx][ny]){
                        q.add(new Point(nx,ny));
                        arr[nx][ny] = arr[p.x][p.y] +1;
                        visit[nx][ny] =true;
                    }
                }
            }
        }
        }
}

 

 [해설]
     

 :  import java.awt.*;

 

 :  static int T,size,x,y,x1,y1;  입력값
    static int arr[][];  배열 좌표
    static boolean visit[][];  방문기록
    static int dx[] = {1, 2, 2, 1, -1, -2, -2, -1 };  8개의 초록칸 x 좌표
    static int dy[] = {-2, -1, 1, 2, 2, 1, -1, -2 };  8개의 초록칸 y 좌표
    static Queue<Point> q = new LinkedList<>();  큐 설정

 

 

 :  T=Integer.parseInt(br.readLine());  첫째줄 입력 (테스트 케이스 묶음수)


 :  while(T-->0){  테스트 케이스만큼 묶음 생성
            size=Integer.parseInt(br.readLine());  체스판 크기
            arr=new int[size][size];   체크판 크기만큼 배열좌표 생성
            visit= new boolean[size][size];   방문기록 생성

            st= new StringTokenizer(br.readLine());  한 테스트 케이스 묶음의 두번째 줄
            x=Integer.parseInt(st.nextToken());  현재 위치 x좌표
            y=Integer.parseInt(st.nextToken());  현재 위치 y좌표
            
            st= new StringTokenizer(br.readLine());  한 테스트 케이스 묶음의 첫번째 줄
            x1=Integer.parseInt(st.nextToken());  이동할 위치 x좌표
            y1=Integer.parseInt(st.nextToken());  이동할 위치 y좌표
            
            bfs();  bfs 호출
            
            System.out.println(arr[x1][y1]);  최종 목적지인 x1, y1를 bfs에 넣어 나온 총 횟수 출력
   }
   

 

 :  static void bfs(){
            q.add(new Point(x,y));  위에서 입력값으로 받은 현재 위치 좌표 x,y 큐에 넣기 
            visit[x][y]= true;  해당위치 방문처리
        
            while(!q.isEmpty()){  큐가 빌 때까지
               

                 Point p = q.poll();  큐에서 뺀 값들 p에 저장
               

                 for(int i =0; i<8;i++){  초록칸의 8방향 탐색
                     int nx = p.x + dx[i];  새로 이동할 x 좌표 = 큐에서 뺀 현재 x값 + 갈 수 있는 x 방향
                     int ny = p.y + dy[i];  새로 이동할 y 좌표 = 큐에서 뺀 현재 y값 + 갈 수 있는 y 방향
                 

                     if(nx>=0 && ny>=0 && nx < size && ny <size){  체스 이동이 0 ~ size (체스판만큼) 으로 제한
                            if(!visit[nx][ny]){  방문처리가 안되어 있다면 
                                  q.add(new Point(nx,ny));  큐에 새로운 현위치 저장
                                  arr[nx][ny] = arr[p.x][p.y] +1; arr배열 값 지정한 적 X (즉 0부터 시작) → 횟수 = 0+1
                                  visit[nx][ny] =true;  해당 위치 방문처리하기
                            }      
                     }
                }
            }

 

 

[코드2]

import java.io.*;
import java.util.*;
import java.awt.*;
public class Main{
    static int dx[] = {1, 2, 2, 1, -1, -2, -2, -1 };
    static int dy[] = {-2, -1, 1, 2, 2, 1, -1, -2 };
    static int count,I;
    static Point start, end;
    static boolean visit[][];
    public static void main(String[] args)throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int T = Integer.parseInt(br.readLine());
        
        while(T-->0){
            I = Integer.parseInt(br.readLine());
            
            StringTokenizer st = new StringTokenizer(br.readLine());
            start = new Point(Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken()));
		    
            st = new StringTokenizer(br.readLine());
            end = new Point(Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken()));
			count =0;
            visit = new boolean[I][I];
        
            System.out.println(bfs(start));
        }
        
    }
    
    static int bfs(Point start){
       
        Queue <Point> q = new LinkedList<>();
        q.add(start);
        visit[start.x][start.y]=true;
        
        
        while(!q.isEmpty()){
            int size = q.size();
            for(int j=0;j<size;j++){
                 Point p = q.poll();
                if(p.x==end.x&&p.y==end.y){
                    return count;
                }
                for(int i=0; i<8;i++){
                    int nextx=p.x+dx[i];
                    int nexty=p.y+dy[i];
                    if(0<=nextx&&nextx<I && 0<=nexty&&nexty<I && !visit[nextx][nexty]){
                        q.add(new Point(nextx,nexty));
                        visit[nextx][nexty]=true;
                    }
                }
            }
            count++;
        }
        return count;
    }
}

 

 [짧은 설명]

 

 - 입력 자체를 Point 함수를 통해 받는다 

 

 - 한바퀴 돌 때마다 큐에서 몇개의 좌표를 받을지 예상할 수 없다 → 큐사이즈 매번 저장하기
   (갈 수 있는 방향이 8개이므로 8번 이동 가능하지만 음수가 아니며, 체스판 안에 포함되어있고,
    아직 방문하지 않은 조건에 포함되는 좌표들이 몇 개일지 모르므로)

 

 - count++는 큐에 추가하는 시점이 아닌 큐에서 빼서 모든 좌표를 확인하고 난 다음에 넣어줘야 한다

   즉 내가 1회에 갈 수 있는 방향이 최대 8개인데 여러개의 좌표를 하나씩 대입해보며 종료조건이 되는지 확인한다

   좌표마다 count 되는 것이 아니라 이 여러개의 좌표 중 내가 선택해서 가야할 길은 딱 하나의 좌표이기 때문에

   count를 뒤에 배치하는 것이다

 

 

 [해설]
     

 :  import java.awt.*;

 

 :  static int count,I;  입력값
    static Point start, end;  현재좌표, 도착좌
    static boolean visit[][];  방문기록
    static int dx[] = {1, 2, 2, 1, -1, -2, -2, -1 };  8개의 초록칸 x 좌표
    static int dy[] = {-2, -1, 1, 2, 2, 1, -1, -2 };  8개의 초록칸 y 좌표

 

 :   int T=Integer.parseInt(br.readLine());  첫째줄 입력 (테스트 케이스 묶음수)


 :  while(T-->0){  테스트 케이스만큼 묶음 생성
            I = Integer.parseInt(br.readLine()); 체스판 크기
            visit= new boolean[size][size];   방문기록 생성

            st= new StringTokenizer(br.readLine()); 
            start = new Point(Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken()));  현위치
    
            
            st= new StringTokenizer(br.readLine());  
            end = new Point(Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken()));  목표위치

 

            visit = new boolean[I][I];  매 테스트 케이스마다 방문기록 초기화

            count =0; 카운트 초기화
            
            System.out.println(bfs(start)); 출력
   }
   

 

 :  static int bfs(Point start){

            Queue <Point> q = new LinkedList<>();  큐생성
            q.add(start); 현재 위치 좌표 큐에 넣기 
            visit[start.x][start.y]=true;  해당위치 방문처리
      
            while(!q.isEmpty()){  큐가 빌 때까지

                 int size = q.size();  매번 큐사이즈 저장하고 시작
                 for(int j=0;j<size;j++){  큐사이즈 만큼 반복
                       Point p = q.poll();  큐에서 뺀 값들 p에 저장
                       if(p.x==end.x&&p.y==end.y){  종료조건
                          return count;  count 출력
                       }

                       for(int i=0; i<8;i++){
                           int nextx=p.x+dx[i];  새로 이동할 x 좌표 = 큐에서 뺀 현재 x값 + 갈 수 있는 x 방향
                           int nexty=p.y+dy[i];  새로 이동할 y 좌표 = 큐에서 뺀 현재 y값 + 갈 수 있는 y 방향
                           if(0<=nextx&&nextx<I && 0<=nexty&&nexty<I && !visit[nextx][nexty]){
                                q.add(new Point(nextx,nexty));  큐에 새로운 현위치 저장
                                visit[nextx][nexty]=true;  해당 위치 방문처리
                           }
                       }
                 }

                 count++;
            }

            return count;

    }

 

 

이제 풀어보러 갈께요 :)

 

 

https://www.acmicpc.net/problem/7562

 

7562번: 나이트의 이동

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

www.acmicpc.net

 

 

* 독학으로 익히는 코딩이라 틀린 것이 있을 수 있습니다. 오류가 있다면 댓글을 통해 알려주세요. 감사합니다. *