-
프로그래머스 시험장 나누기, 백준 21610Java/코딩테스트 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; } } }
'Java > 코딩테스트' 카테고리의 다른 글
프로그래머스 전력망을 둘로 나누기, 베스트앨범, 의상 (0) 2023.09.26 백준 2133, 2141 (0) 2023.09.20 백준 2636, 1339, 2110 (0) 2023.09.05 백준 3055, 1600, 7576 (0) 2023.08.30 백준 2140, 28303, 2258 (0) 2023.08.22