Algorithm/ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€

ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€ - μ•„μ΄ν…œ 쀍기

giraffe_ 2023. 8. 21. 15:15

https://school.programmers.co.kr/learn/courses/30/lessons/87694

 

ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€

μ½”λ“œ μ€‘μ‹¬μ˜ 개발자 μ±„μš©. μŠ€νƒ 기반의 ν¬μ§€μ…˜ λ§€μΉ­. ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€μ˜ 개발자 λ§žμΆ€ν˜• ν”„λ‘œν•„μ„ λ“±λ‘ν•˜κ³ , λ‚˜μ™€ 기술 ꢁ합이 잘 λ§žλŠ” 기업듀을 λ§€μΉ­ λ°›μœΌμ„Έμš”.

programmers.co.kr

 

 

 

 

 

 

문제

좜처 : ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€ μ•„μ΄ν…œ 쀍기

 

 

  • μ§€ν˜•μ€ 각 변이 xμΆ•, yμΆ•κ³Ό ν‰ν–‰ν•œ μ§μ‚¬κ°ν˜•μ΄ 겹쳐진 ν˜•νƒœλ‘œ ν‘œν˜„
  • μΊλ¦­ν„°λŠ” 이 λ‹€κ°ν˜•μ˜ λ‘˜λ ˆ(ꡡ은 μ„ )λ₯Ό λ”°λΌμ„œ μ΄λ™ν•œλ‹€.
    • 쀑앙에 빈 곡간이 μƒκΈ°λŠ” 경우, λ‹€κ°ν˜•μ˜ κ°€μž₯ λ°”κΉ₯μͺ½ ν…Œλ‘λ¦¬κ°€ μΊλ¦­ν„°μ˜ 이동 κ²½λ‘œκ°€ λœλ‹€.
    • μ„œλ‘œ λ‹€λ₯Έ 두 μ§μ‚¬κ°ν˜•μ΄ κΌ­μ§“μ μ—μ„œ λ§Œλ‚˜κ±°λ‚˜, 변이 κ²ΉμΉ˜λŠ” 경우 등은 μ—†λ‹€.
    • μ§€ν˜•μ΄ 2개 μ΄μƒμœΌλ‘œ λΆ„λ¦¬λœ κ²½μš°λ„ μ—†λ‹€.
    • ν•œ μ§μ‚¬κ°ν˜•μ΄ λ‹€λ₯Έ μ§μ‚¬κ°ν˜• μ•ˆμ— μ™„μ „νžˆ ν¬ν•¨λ˜λŠ” 경우 λ˜ν•œ μ—†λ‹€.
  • rectangle의 μ›μ†ŒλŠ” 각 μ§μ‚¬κ°ν˜•μ˜ [쒌츑 ν•˜λ‹¨ x, 쒌츑 ν•˜λ‹¨ y, 우츑 상단 x, 우츑 상단 y] μ’Œν‘œ ν˜•νƒœλ‘œ μ£Όμ–΄μ§„λ‹€.
  • 초기 μΊλ¦­ν„°μ˜ μœ„μΉ˜ characterX, characterY, μ•„μ΄ν…œμ˜ μœ„μΉ˜ itemX, itemYκ°€ μ£Όμ–΄μ§„λ‹€.
  • 캐릭터가 μ•„μ΄ν…œμ„ 쀍기 μœ„ν•΄ 이동해야 ν•˜λŠ” κ°€μž₯ 짧은 거리 κ΅¬ν•˜κΈ°.

 

μ œν•œμ‚¬ν•­

  • μ§μ‚¬κ°ν˜•μ„ λ‚˜νƒ€λ‚΄λŠ” λͺ¨λ“  μ’Œν‘œκ°’μ€ 1 이상 50 μ΄ν•˜μΈ μžμ—°μˆ˜
  • charcterX, charcterYλŠ” 1 이상 50 μ΄ν•˜μΈ μžμ—°μˆ˜
  • itemX, itemYλŠ” 1 이상 50 μ΄ν•˜μΈ μžμ—°μˆ˜

 

 

 

 

 

풀이

μ’Œν‘œκ³„λ₯Ό κ·Έλž˜ν”„λ‘œ ν‘œν˜„ν•˜κ³ , λ°”κΉ₯μͺ½ ν…Œλ‘λ¦¬λ₯Ό ꡬ해 κ·Έλž˜ν”„ 탐색을 μ΄μš©ν•˜μ—¬ μ΅œλ‹¨κ±°λ¦¬λ₯Ό κ΅¬ν•˜λŠ” λ¬Έμ œμ΄λ‹€.

 

이 문제의 핡심은 κ°€μž₯ λ°”κΉ₯μͺ½ ν…Œλ‘λ¦¬λ₯Ό κ΅¬ν•˜λŠ” 것이닀. 처음 ν…Œλ‘λ¦¬λ₯Ό κ΅¬ν•˜λŠ” 풀이 방법을 λ– μ˜¬λ¦¬λ‹€κ°€ μ˜ˆμ „μ— ν’€μ—ˆλ˜ λ°±μ€€ 치즈 문제(https://www.acmicpc.net/problem/2636)κ°€ 생각이 났닀. 치즈 λ¬Έμ œμ—μ„œλ„ λ°”κΉ₯μͺ½ ν…Œλ‘λ¦¬λ₯Ό κ΅¬ν–ˆμ–΄μ•Ό ν–ˆλ‹€. κ·Έλž˜μ„œ μΉ˜μ¦ˆκ°€ μžˆλŠ” μ’Œν‘œμ— λŒ€ν•΄ 4λ°© 탐색을 ν•΄μ„œ, 빈 곡간이 있으면 ν…Œλ‘λ¦¬λΌκ³  ν‘œμ‹œλ₯Ό ν–ˆλ‹€.

 

 μ΄ λ¬Έμ œμ—λ„ 이 풀이λ₯Ό μ μš©ν•˜λ €κ³  ν–ˆμ—ˆλ‹€. ν•˜μ§€λ§Œ 변이 직각으둜 κΊΎμ΄λŠ” μ§€μ μ—μ„œμ˜ μ’Œν‘œμ— λŒ€ν•΄μ„œλŠ” 4λ°© 탐색을 ν–ˆμ„ λ•Œ, 빈 곡간이 μ•„λ‹ˆλΌ λͺ¨λ‘ 점이닀. 치즈 λ¬Έμ œμ—μ„œλŠ” λ©΄μ΄λΌμ„œ κ°€λŠ₯ν–ˆμ§€λ§Œ, 이 λ¬Έμ œμ—μ„œλŠ” μ μ΄λΌμ„œ 적용이 μ–΄λ ΅λ‹€.

 

 κ·Έλ¦¬κ³  치즈 λ¬Έμ œμ—μ„œλŠ” μ²˜μŒλΆ€ν„° 치즈의 κ·Έλž˜ν”„κ°€ μ£Όμ–΄μ‘Œλ‹€. ν•˜μ§€λ§Œ 이 λ¬Έμ œμ—μ„œλŠ” μ§μ‚¬κ°ν˜• μ–‘ 끝점의 μ’Œν‘œ 값이 μ£Όμ–΄μ§€λ―€λ‘œ κ·Έλž˜ν”„λ₯Ό 그리고, 탐색을 ν•˜λŠ” 과정은 μ‹œκ°„μ΄ 였래걸렀 λΉ„νš¨μœ¨μ μ΄λ‹€.

 

 

  • κ·Έλž˜ν”„ ν‘œν˜„
    • int ν˜•μ˜ 2차원 λ°°μ—΄λ‘œ 각 μ’Œν‘œκ°’μ„ 빈 κ³³(0), μ§μ‚¬κ°ν˜• λ‚΄λΆ€(1), λ°”κΉ₯μͺ½ ν…Œλ‘λ¦¬(2)둜 ν‘œν˜„ν˜„λ‹€. 

 

  • κ°€μž₯ λ°”κΉ₯μͺ½ ν…Œλ‘λ¦¬ κ΅¬ν•˜κΈ°
    • μž…λ ₯으둜 λ“€μ–΄μ˜€λŠ” μ§μ‚¬κ°ν˜•μ˜ μ’Œν‘œκ°’μœΌλ‘œ λ°˜λ³΅λ¬Έμ„ λŒλ¦°λ‹€
      • μ’Œν‘œκ°€ ν…Œλ‘λ¦¬μΈ 경우 : 빈 κ³³(0)일 λ•Œλ§Œ ν…Œλ‘λ¦¬(2)λ₯Ό κ·Έλ¦°λ‹€. 이미 λ‚΄λΆ€λ‘œ μΉ ν•œ 경우(1)라면, 선을 그릴 μˆ˜κ°€ μ—†κΈ° λ•Œλ¬Έμ΄λ‹€.
      • μ’Œν‘œκ°€ μ§μ‚¬κ°ν˜• 내뢀인 경우 : μ§μ‚¬κ°ν˜•μ΄ κ²ΉμΉ  수 μžˆμœΌλ―€λ‘œ ν…Œλ‘λ¦¬(2) 상관없이 λͺ¨λ‘ λ‚΄λΆ€(1)둜 μΉ ν•œλ‹€. 

 

 

μ΄λ ‡κ²Œ κ·Έλž˜ν”„λ₯Ό λ§Œλ“€κ³ , BFS 탐색을 돌리렀고 ν–ˆλ‹€. ν•˜μ§€λ§Œ νƒμƒ‰μ‹œ κ±Έλ¦¬λŠ” 뢀뢄이 μžˆλ‹€.

 

1) λ°”κΉ₯μͺ½ ν…Œλ‘λ¦¬κ°€ γ„·μžλ‘œ λ˜μ–΄μžˆλŠ” λΆ€λΆ„

ν•œ 점에 λŒ€ν•΄ 4λ°© 탐색을 ν•  λ•Œ, μ„ μœΌλ‘œ μ—°κ²°λ˜μ–΄ μžˆμ§€ μ•Šμ§€λ§Œ ν•΄λ‹Ή 지점은 ν…Œλ‘λ¦¬μ΄λ―€λ‘œ 이동이 κ°€λŠ₯ν•΄μ§€κ²Œ λœλ‹€.

 

 

2) 쀑앙에 빈 곡간이 있고, 면적이 1인 경우

ν•œ 점에 λŒ€ν•΄ 4λ°© 탐색을 ν•  λ•Œ, μ•ˆ μͺ½ ν…Œλ‘λ¦¬λ‘œλ„ 이동이 κ°€λŠ₯ν•΄μ§„λ‹€. λ°”κΉ₯μͺ½ ν…Œλ‘λ¦¬λ§Œ 이동이 κ°€λŠ₯ν•˜λ―€λ‘œ μ•ˆλœλ‹€.

 

 

 

 

이λ₯Ό ν•΄κ²°ν•  방법을 계속 생각해보닀가 λ„μ €νžˆ 생각할 μˆ˜κ°€ μ—†μ–΄μ„œ 문제 λ‚΄μ˜ μ§ˆλ¬Έν•˜κΈ° κ²Œμ‹œνŒμ— μžˆλŠ” ν•œ 글을 λ΄€λ‹€.

(https://school.programmers.co.kr/questions/21253)

 

μ’Œν‘œλ₯Ό 2배둜 ν™•μž₯μ‹œμΌœ μ ‘κ·Όν•˜λΌλŠ” νžŒνŠΈκ°€ μžˆμ—ˆλ‹€. μ’Œν‘œλ₯Ό 2배둜 ν™•μž₯μ‹œν‚€λ©΄ μœ„μ—μ„œ μ–ΈκΈ‰ν–ˆλ˜ λ¬Έμ œκ°€ ν•΄κ²°λœλ‹€.

 

 

ν…Œλ‘λ¦¬μ— 해당이 λ˜μ–΄ ν•œμΉΈμœΌλ‘œ 이동이 κ°€λŠ₯ν•΄μ‘Œλ˜ 곳이 2배둜 λŠ˜λ Έλ”λ‹ˆ ν•œμΉΈμœΌλ‘œ 이동이 λΆˆκ°€λŠ₯ν•΄μ§€κ²Œ λœλ‹€.

 

 

 

  • μ’Œν‘œκ³„λ₯Ό 2배둜 ν™•μž₯ν•˜κΈ°
    • κ·Έλž˜ν”„ 크기λ₯Ό 2배둜 λ§Œλ“€κΈ° : μ œν•œμ‚¬ν•­μ—μ„œ 1이상 50μ΄ν•˜μ˜ μžμ—°μˆ˜μ΄λ―€λ‘œ ν¬κΈ°λŠ” 50*2+1인 101이 λœλ‹€.
    • μ§μ‚¬κ°ν˜•μ˜ μ’Œν‘œκ°’μ„ 2λ°°ν•˜μ—¬ ν…Œλ‘λ¦¬μ™€ λ‚΄λΆ€ μ±„μš°κΈ°
    • 2배된 μ’Œν‘œκ°’μœΌλ‘œ κ·Έλž˜ν”„ νƒμƒ‰ν•˜κΈ°

 

 

  • BFS 탐색
    • μ΅œμ†Œ 이동을 κ΅¬ν•˜λŠ” κ²ƒμ΄λ―€λ‘œ λ„ˆλΉ„μš°μ„ νƒμƒ‰μ΄ μ ν•©ν•˜λ‹€.
    • 큐λ₯Ό λŒλ¦΄μ‹œ 맀번 큐의 μ‚¬μ΄μ¦ˆλ§ŒνΌ λŠμ–΄μ„œ νƒμƒ‰ν•œλ‹€.
    • 큐에 μ‹œμž‘μ μ„ λ‹΄μ•„ 4방으둜 νƒμƒ‰ν•˜λ©°, ν…Œνˆ¬λ¦¬μΌ μ‹œ 큐에 λ‹΄μ•„ 계속 νƒμƒ‰ν•œλ‹€.
    • λ„μ°©ν–ˆλ‹€λ©΄ λ°”λ‘œ 이동 횟수λ₯Ό return ν•œλ‹€. (μ΅œμ†Ÿκ°’μ„ κ΅¬ν•˜λŠ” κ²ƒμ΄λ―€λ‘œ 더 이상 탐색할 ν•„μš”κ°€ μ—†λ‹€.)

 

 

 

 

 

μ½”λ“œ

import java.util.*;

class Solution {
    static int[][] graph; //κ·Έλž˜ν”„ : 0, 1(λ‚΄λΆ€), 2(ν…Œλ‘λ¦¬)
    static boolean[][] visited;
    static int[] di = {-1, 1, 0, 0};
    static int[] dj = {0, 0, -1, 1};
    
    static class Point {
        int i, j; //yμ’Œν‘œ(ν–‰), xμ’Œν‘œ(μ—΄)
        
        Point(int i, int j) {
            this.i = i;
            this.j = j;
        }
    }
    
    public int solution(int[][] rectangle, int characterX, int characterY, int itemX, int itemY) {
        graph = new int[50*2+1][50*2+1];
        
        //κ·Έλž˜ν”„ μ˜μ—­ μ±„μš°κΈ°
        for(int[] r : rectangle) {
            int x1 = r[0]*2; //쒌츑 ν•˜λ‹¨ x
            int y1 = r[1]*2; //쒌츑 ν•˜λ‹¨ y
            int x2 = r[2]*2; //우츑 상단 x
            int y2 = r[3]*2; //우츑 상단 y
            
            for(int i = y1; i <= y2; i++) {
                for(int j = x1; j <= x2; j++) {
                    if(i == y1 || i == y2 || j == x1 || j == x2) { //μ’Œν‘œκ°€ ν…Œλ‘λ¦¬
                        if(graph[i][j] == 0) { //빈 곳
                            graph[i][j] = 2; //ν…Œλ‘λ¦¬ 그리기
                        }
                    } else { //μ’Œν‘œκ°€ λ‚΄λΆ€
                        graph[i][j] = 1; //λ‚΄λΆ€ μΉ ν•˜κΈ°        
                    }
                }
            }
        }
        
        //κ·Έλž˜ν”„ 탐색
        visited = new boolean[50*2+1][50*2+1];
        
        int answer = bfs(characterX * 2, characterY * 2, itemX * 2, itemY * 2) / 2; //2λ°° λŠ˜λ ΈμœΌλ‹ˆ 2둜 λ‚˜λˆ„κΈ°
        return answer;
    }
    
    public int bfs(int characterX, int characterY, int itemX, int itemY) {
        Queue<Point> queue = new LinkedList<>();
        
        queue.add(new Point(characterY, characterX));
        visited[characterY][characterX] = true;
        
        int count = 0; //이동 카운트
        while(!queue.isEmpty()) {
            int size = queue.size(); //λ„ˆλΉ„ 탐색을 μœ„ν•œ μ‚¬μ΄μ¦ˆ
            
            for(int s = 0; s < size; s++) { //μ‚¬μ΄μ¦ˆλ§ŒνΌ λŠμ–΄μ„œ 탐색
                Point point = queue.poll();
                
                if(point.i == itemY && point.j == itemX) { //도착
                    return count;
                }
                
                for(int d = 0; d < 4; d++) {
                    int ni = point.i + di[d];
                    int nj = point.j + dj[d];
                    
                    if(1 <= ni && ni <= 100 && 1 <= nj && nj <= 100) {
                        if(!visited[ni][nj] && graph[ni][nj] == 2) {
                            queue.add(new Point(ni, nj));
                            visited[ni][nj] = true;
                        }
                    }
                }
            }
            
            count++;
        } 
        
        return count;
    }
}

 

 

 

 

 

κ²°κ³Ό

 

 

 

 

 

배운점

  • μ’Œν‘œκ³„λ₯Ό 2배둜 λŠ˜λ¦¬λŠ” 방법도 있음
  • x, y와 ν–‰, μ—΄ ν—·κ°ˆλ¦Ό μ£Όμ˜ν•˜κΈ°. κ°œλ…μ΄ λ°˜λŒ€λΌμ„œ μ½”λ“œ μž‘μ„±μ‹œ μ£Όμ˜κ°€ ν•„μš”ν•˜λ‹€.