Java/코딩테스트

프로그래머스 시험장 나누기, 백준 21610

Bubbles 2023. 9. 19. 03:00

🤣 프로그래머스 : 시험장 나누기 

사실 이것은 ... 직접 푼 문제는 아니긴 하다.

하지만 그냥 공부한 셈 치고 정리 겸 올려 본다... 카카오 코테 문제이고, 오랜만에 프로그래머스 들어갔다가 추천 문제라며 띄워주길래 그냥 하나 풀어봐야겠다~ 하고 푸는데 답이 도저히 안 나와서 해설을 찾았다...

걍 고수의 풀이를 보고 이해한거 정리한 거라고 생각하면 된다. 

보니깐 마지막 문제로 나온거던데 여기까지 가지도 못하고 끝나지 않았을까 싶다. 

 

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

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

이분의 해설과 코드를 보고 풀었다. 잘 정리가 되어 있으니 참고하길.. 

https://blog.encrypted.gg/1003

 

[2021 카카오 채용연계형 인턴십] Q5. 시험장 나누기 (C++, Python, Java)

문제 링크 https://programmers.co.kr/learn/courses/30/lessons/81305 예상 난이도 P5 알고리즘 분류 트리, 그리디, Parametric Search 풀이 보통 코딩테스트 문제에서 5분 이상 풀이를 못잡고 있는 일이 잘 없는데 이

blog.encrypted.gg

 

 

문제 유형이 Parametric Search 인데 이 유형은 이전에 풀었던 2110 공유기 문제와 동일한 유형이다. https://bubblebubble.tistory.com/109 

이 문제는 각 그룹의 수를 x명으로 하는 경우에 그룹의 수가 K개 이하라는 문제조건을 만족하는가? 만족하면 x 기준을 더 낮게 잡고 아니면 더 높이는 방식으로 최적의 X명을 찾아간다.

이 그룹당 최대 인원수를 이진탐색을 통해 제한했다면, 각 그룹의 개수는 DFS 통해서 카운트 할 수 있다. 연결된 애들을 다 탐색하고 돌기 오기 때문이다! 

 

 

전체코드 : 매우... 간결하다. 

import java.util.*;
class Solution {
    int[] left = new int[10001];
    int[] right = new int[10001];
    int[] parent = new int[10001];
    int[] value = new int[10001];
    int n, root;
    int count = 0;
    
    public int solution(int k, int[] num, int[][] links) {
        n = num.length;
        for (int i = 0; i < n; i++) {
            parent[i] = -1;
        }
        for (int i = 0; i < n; i++) {
            left[i] = links[i][0];
            right[i] = links[i][1];
            value[i] = num[i];
            
            if (left[i] != -1) 
                parent[left[i]] = i;
            if (right[i] != -1)
                parent[right[i]] = i;
        }
        
        for (int i = 0; i < n; i++) {
            if (parent[i] == -1) {
                root = i;
                break;
            }
        }
        
        int start = value[0];
        int end = (int)1e8;
        for (int i = 0; i < n; i++) {
            if (start < value[i]) {
                start = value[i];
            }
            
        }
        
        while (start < end) {
            int mid = (start + end) / 2;
            int temp = calculate(mid);
            if (temp <= k) {
                end = mid;
            } else {
                start = mid+1;
            }
        }
        
        return start;
    }
    
    public int calculate(int limit) {
        count = 0;
        DFS(root, limit);
        
        count++;
        return count;
    }
    
    public int DFS(int index, int limit) {
        int leftChild = 0;
        if (left[index] != -1) {
            leftChild = DFS(left[index], limit);
        }
        
        int rightChild = 0;
        if (right[index] != -1) {
            rightChild = DFS(right[index], limit);
        }
        
        if (rightChild + leftChild + value[index] <= limit) {
            return rightChild + leftChild + value[index];
        } else if (Math.min(rightChild, leftChild) + value[index] <= limit) {
            count++;
            return Math.min(rightChild, leftChild) + value[index];
        } else {
            count += 2;
            return value[index];
        }
    }
}

 

 


🦈 백준 21610 : 마법사 상어와 비바라기 

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

 

21610번: 마법사 상어와 비바라기

마법사 상어는 파이어볼, 토네이도, 파이어스톰, 물복사버그 마법을 할 수 있다. 오늘 새로 배운 마법은 비바라기이다. 비바라기를 시전하면 하늘에 비구름을 만들 수 있다. 오늘은 비바라기

www.acmicpc.net

비바라기를 보면 포켓* 기술이 생각난다. 말 그대로 필드에 비 내리게 하는 기술

 

🦈 삼성 기출문제중에 골드 5로 난이도만 보면 나름 쉬워보이지만... 삼성 기출들이 다 그렇듯, 조건이 많다보니 빼먹으면 아주... 헤매게 되어 있는 문제이다. 그리고 난 항상 빼먹는다. 진짜 배열 다 그려가면서 어디가 틀린건지 찾았는데 매우 허무했다.

🦈 메인 로직은 아래 처럼 구성되어 있다.

🦈 구름 움직이기 - 비 내리기 - 물 복사 마법 - 구름 위치 초기화 - 다음 구름 위치 cloud 리스트에 넣어줌 - 방문배열 초기화(이전에 구름이 생겼던 곳은 다음 구름 초기 위치가 될 수 없다!)

moveCloud(dir, length);
makeRain();
waterCopy();
clouds = new ArrayList<>();
findCloudPos();
visited = new boolean[n][n];

🦈 구름 움직이기

  • 기존 clouds 리스트에는 일단 초기에 지정한 구름 발생 위치가 담겨 있다. 
  • 각 위치들 하나하나가 다 방향에 맞춰 일괄 이동해야 하는데 무슨 군집형태로 이동하는 것도 아니기 때문에 일일이 이동시켜준 뒤, 이동된 좌표를 다시 clouds에 넣어주었다. 
private static void moveCloud(int dir, int length) {
        List<Pos> newCloud = new ArrayList<>();
        for (Pos cloud : clouds) {
            int nextX = (cloud.x + dirX[dir-1] * length) % n;
            if (nextX < 0) {
                nextX += n;
            }
            int nextY = (cloud.y + dirY[dir-1] * length) % n;
            if (nextY < 0) {
                nextY += n;
            }
            if (visited[nextX][nextY]) {
                continue;
            }
            newCloud.add(new Pos(nextX, nextY));
            visited[nextX][nextY] = true;
        }
        clouds = new ArrayList<>(newCloud);
}

 

 

🦈 makeRain은 그냥 비 내리게 하는 함수이다. 각 map 칸에 +1 해주는 로직

private static void makeRain() {
        for (Pos cloud : clouds) {
            map[cloud.x][cloud.y]++;
        }
}

 

🦈 waterCopy 

  • 대각선 4방향은 dir 값이 2, 4, 6, 8이다. 나는 그냥 방향을 0부터 시작해서 구현했으므로 각 비온 자리마다 1,3,5,7 방향으로 탐색해주면 된다. 
  • 여기서는 넘어가는게 허용되지 않는다. (맨 끝에서 대각선되면 다른 대각선으로 넘어가고 이런거)
    • 이게 허용되지 않아서 골드 5인가 싶기도..? 
  • 쨌든 그래서 범위를 벗어나거나, 바구니 칸 물이 0이라면 내버려두고, count 개수 센 다음 addRain 리스트에 더해준다.
    • 이것도 한번에 계속 차례대로 더하면 다음 좌표가 영향을 받을 수 있으므로, 따로 리스트에 빼서 넣어주고 마지막 for문에서 한번에 넣어주는 것
private static void waterCopy() {
        List<Integer> addRain = new ArrayList<>();
        for (Pos cloud : clouds) {
            int count = 0;
            for (int i = 1; i < 8; i += 2) {
                int nextX = cloud.x + dirX[i];
                int nextY = cloud.y + dirY[i];

                if (nextX < 0 || nextX >= n || nextY < 0 || nextY >= n) {
                    continue;
                }
                if (map[nextX][nextY] == 0) {
                    continue;
                }
                count++;
            }
            addRain.add(count);
        }

        for (int i = 0; i < addRain.size(); i++) {
            map[clouds.get(i).x][clouds.get(i).y] += addRain.get(i);
        }
    }

 

🦈 findCloudPos 

  • 이전에 구름 있던 장소(visited true)가 아니고, 물의 양이 2 이상인 경우에만 구름 초기 위치로 지정해준다. 
private static void findCloudPos() {
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (visited[i][j]) {
                    continue;
                }
                if (map[i][j] >= 2) {
                    map[i][j] -= 2;
                    clouds.add(new Pos(i, j));
                }
            }
        }
}

 

🦈 전체 코드 

import java.io.*;
import java.util.*;
public class p21610 {
    private static int[] dirX = { 0, -1, -1, -1, 0, 1, 1, 1 };
    private static int[] dirY = { -1, -1, 0, 1, 1, 1, 0, -1 };
    private static int n, m;
    private static List<Pos> clouds;
    private static int[][] map;
    private static boolean[][] visited;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        n = Integer.parseInt(st.nextToken());
        m = Integer.parseInt(st.nextToken());

        clouds = new ArrayList<>();
        map = new int[n][n];
        visited = new boolean[n][n];

        int answer = 0;

        for (int i = 0; i < n; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j < n; j++) {
                map[i][j] = Integer.parseInt(st.nextToken());
            }
        }

        clouds.add(new Pos(n-1, 0));
        clouds.add(new Pos(n-1, 1));
        clouds.add(new Pos(n-2, 0));
        clouds.add(new Pos(n-2, 1));

        for (int i = 0; i < m; i++) {
            st = new StringTokenizer(br.readLine());
            int dir = Integer.parseInt(st.nextToken());
            int length = Integer.parseInt(st.nextToken());

            moveCloud(dir, length);
            makeRain();
            waterCopy();
            clouds = new ArrayList<>();
            findCloudPos();
            visited = new boolean[n][n];
        }

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                answer += map[i][j];
            }
        }

        System.out.println(answer);
    }

    private static void findCloudPos() {
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (visited[i][j]) {
                    continue;
                }
                if (map[i][j] >= 2) {
                    map[i][j] -= 2;
                    clouds.add(new Pos(i, j));
                }
            }
        }
    }
    private static void moveCloud(int dir, int length) {
        List<Pos> newCloud = new ArrayList<>();
        for (Pos cloud : clouds) {
            int nextX = (cloud.x + dirX[dir-1] * length) % n;
            if (nextX < 0) {
                nextX += n;
            }
            int nextY = (cloud.y + dirY[dir-1] * length) % n;
            if (nextY < 0) {
                nextY += n;
            }
            if (visited[nextX][nextY]) {
                continue;
            }
            newCloud.add(new Pos(nextX, nextY));
            visited[nextX][nextY] = true;
        }
        clouds = new ArrayList<>(newCloud);
    }

    private static void makeRain() {
        for (Pos cloud : clouds) {
            map[cloud.x][cloud.y]++;
        }
    }

    private static void waterCopy() {
        List<Integer> addRain = new ArrayList<>();
        for (Pos cloud : clouds) {
            int count = 0;
            for (int i = 1; i < 8; i += 2) {
                int nextX = cloud.x + dirX[i];
                int nextY = cloud.y + dirY[i];

                if (nextX < 0 || nextX >= n || nextY < 0 || nextY >= n) {
                    continue;
                }
                if (map[nextX][nextY] == 0) {
                    continue;
                }
                count++;
            }
            addRain.add(count);
        }

        for (int i = 0; i < addRain.size(); i++) {
            map[clouds.get(i).x][clouds.get(i).y] += addRain.get(i);
        }
    }

    private static class Pos {
        int x;
        int y;
        public Pos (int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
}