From 3c4180f45780f1bd68b1f99eacd1d472fb95d1ef Mon Sep 17 00:00:00 2001 From: "YeJun, Jung" <31740224+yejun614@users.noreply.github.com> Date: Wed, 4 Feb 2026 08:51:01 +0900 Subject: [PATCH 1/5] feat: add heap sort examples for java --- notes/java/heap_sort.java | 102 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 notes/java/heap_sort.java diff --git a/notes/java/heap_sort.java b/notes/java/heap_sort.java new file mode 100644 index 0000000..0630049 --- /dev/null +++ b/notes/java/heap_sort.java @@ -0,0 +1,102 @@ +package practice.heap; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class Program { + private static class PriorityQueue> { + private List memory = new ArrayList<>(); + + public PriorityQueue() { memory.add(null); } + + public void push(T item) { + memory.add(item); + + int index = memory.size() - 1; + int parentIndex = index / 2; + + while (parentIndex >= 1 && compareIndex(parentIndex, item)) { + Collections.swap(memory, parentIndex, index); + + index = parentIndex; + parentIndex /= 2; + } + } + + public T pop() { + final T item = memory.get(1); + int last = memory.size() - 1; + + memory.set(1, memory.get(last)); + memory.remove(last--); + + int index = 1; + int childIndex = getChildIndex(index * 2); + + while (childIndex <= last && compareIndex(index, childIndex)) { + Collections.swap(memory, index, childIndex); + + index = childIndex; + childIndex = getChildIndex(index * 2); + } + + return item; + } + + private boolean compareIndex(int indexA, int indexB) { + return memory.get(indexA).compareTo(memory.get(indexB)) > 0; + } + + private boolean compareIndex(int indexA, T value) { + return memory.get(indexA).compareTo(value) > 0; + } + + private int getChildIndex(int index) { + final int size = memory.size(); + if (index >= size) return size; + if (index == size - 1) return index; + if (compareIndex(index, index + 1)) index++; + return index; + } + + public boolean isEmpty() { return memory.size() < 2; } + @Override public String toString() { return "PriorityQueue " + memory; } + } + + private static > Object[] heapSort(T[] arr) { + // 입력된 데이터를 모두 최소 힙에 입력한다 + PriorityQueue priorityQueue = new PriorityQueue<>(); + for (T item : arr) priorityQueue.push(item); + System.out.println(priorityQueue); + + // 최소 힙에 있는 데이터를 모두 pop 하여 정렬한다 + List result = new ArrayList<>(); + while (!priorityQueue.isEmpty()) { + result.add(priorityQueue.pop()); + System.out.println(priorityQueue); + } + + // 결과 반환 + return result.toArray(); + } + + public static void main(String[] args) { + // 정렬할 배열 준비 + Integer[] arr = {4, 3, 5, 6, 3, 6, 899, 32, 54, 6, 7}; + + // 최소 힙 정렬 + Object[] sortedArr = heapSort(arr); + System.out.println(); + + // 정렬 결과를 정수 배열로 변환하여 출력 + Integer[] sortedIntArr = Arrays.copyOf(sortedArr, arr.length, Integer[].class); + System.out.println("heap sort: " + Arrays.toString(sortedIntArr)); + + // 결과 비교 + Arrays.sort(arr); + System.out.println("sort : " + Arrays.toString(arr)); + System.out.println("compare : " + Arrays.equals(arr, sortedIntArr)); + } +} From f10bba5908463a893b10fdf5f34e19c59a671c1d Mon Sep 17 00:00:00 2001 From: "YeJun, Jung" <31740224+yejun614@users.noreply.github.com> Date: Wed, 4 Feb 2026 08:52:38 +0900 Subject: [PATCH 2/5] feat: add bfs and dfs examples for java --- notes/java/bfs-dfs/Program.java | 60 +++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 notes/java/bfs-dfs/Program.java diff --git a/notes/java/bfs-dfs/Program.java b/notes/java/bfs-dfs/Program.java new file mode 100644 index 0000000..2fe5e4f --- /dev/null +++ b/notes/java/bfs-dfs/Program.java @@ -0,0 +1,60 @@ +package practice.bfs; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.List; +import java.util.Queue; +import java.util.Stack; + +public class Program { + public static void main(String[] args) { + /* + * (1) + * / | \ + * (2) (3) (4) + * / \ / | \ + * (5) (6)(7)(8)(9) + */ + final int[][] edges = { // 노드는 1번부터 시작 + {1, 2}, {1, 3}, {1, 4}, + {2, 5}, {2, 6}, + {4, 7}, {4, 8}, {4, 9}, + }; + final int nodeCount = 9; + + // 그래프를 자료형에 저장 + List> graph = new ArrayList<>(); + for (int count = 0; count <= nodeCount; count++) graph.add(new ArrayList<>()); + for (int[] edge : edges) graph.get(edge[0]).add(edge[1]); + + // BFS + Queue bfsQueue = new ArrayDeque<>(); + bfsQueue.offer(1); + + System.out.println("BFS"); + while (!bfsQueue.isEmpty()) { + int nodeIndex = bfsQueue.poll(); + System.out.println(nodeIndex); + + for (int child : graph.get(nodeIndex)) { + bfsQueue.offer(child); + } + } + System.out.println(); + + // DFS + Stack dfsStack = new Stack<>(); + dfsStack.push(1); + + System.out.println("DFS"); + while (!dfsStack.isEmpty()) { + int nodeIndex = dfsStack.pop(); + System.out.println(nodeIndex); + + for (int child : graph.get(nodeIndex)) { + dfsStack.push(child); + } + } + + } +} From 7e1a9efe113fe903429d31c2c0060af51eb46b32 Mon Sep 17 00:00:00 2001 From: "YeJun, Jung" <31740224+yejun614@users.noreply.github.com> Date: Wed, 4 Feb 2026 08:53:25 +0900 Subject: [PATCH 3/5] chore: move directory of heap sort --- notes/java/{heap_sort.java => heap-sort/Program.java} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename notes/java/{heap_sort.java => heap-sort/Program.java} (100%) diff --git a/notes/java/heap_sort.java b/notes/java/heap-sort/Program.java similarity index 100% rename from notes/java/heap_sort.java rename to notes/java/heap-sort/Program.java From 2ea5a38f4a2bf7f77a31c213be951b6b08438eef Mon Sep 17 00:00:00 2001 From: "YeJun, Jung" Date: Wed, 4 Feb 2026 21:46:04 +0900 Subject: [PATCH 4/5] docs: ignore MacOS system file --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 1610bd7..8e17ac6 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ bin/ *.in *.out +# OS +.DS_Store From 755638e34b944e02d8a283210bd9a71c0770b065 Mon Sep 17 00:00:00 2001 From: "YeJun, Jung" Date: Wed, 4 Feb 2026 21:47:28 +0900 Subject: [PATCH 5/5] feat: add algorithm solutions --- problems/SWEA/p1210/Solution.java | 132 +++++++++++++++++++ problems/SWEA/p4130/Solution.java | 205 +++++++++++++++++++++++++++++ problems/SWEA/p6808/Solution.java | 185 ++++++++++++++++++++++++++ problems/baekjoon/p1325/Main.java | 154 ++++++++++++++++++++++ problems/baekjoon/p15649/Main.java | 119 +++++++++++++++++ problems/baekjoon/p5567/Main.java | 121 +++++++++++++++++ 6 files changed, 916 insertions(+) create mode 100644 problems/SWEA/p1210/Solution.java create mode 100644 problems/SWEA/p4130/Solution.java create mode 100644 problems/SWEA/p6808/Solution.java create mode 100644 problems/baekjoon/p1325/Main.java create mode 100644 problems/baekjoon/p15649/Main.java create mode 100644 problems/baekjoon/p5567/Main.java diff --git a/problems/SWEA/p1210/Solution.java b/problems/SWEA/p1210/Solution.java new file mode 100644 index 0000000..c605abb --- /dev/null +++ b/problems/SWEA/p1210/Solution.java @@ -0,0 +1,132 @@ +/* + * (1210) [S/W 문제해결 기본] 2일차 - Ladder1 + * https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV14ABYKADACFAYh&categoryId=AV14ABYKADACFAYh&categoryType=CODE&problemTitle=1210&orderBy=FIRST_REG_DATETIME&selectCodeLang=ALL&select-1=&pageSize=10&pageIndex=1 + */ + +package swea.p1210; + +import java.io.*; +import java.util.*; + +/** + * SW Expert Academy - 1210. [S/W 문제해결 기본] 2일차 - Ladder1 + * @author YeJun, Jung + * + * @see #main(String[]) + * 1. 입출력을 초기화한다. + * 2. 총 10개의 테스트 케이스를 반복 처리한다. + * 3. 각 테스트 케이스의 번호를 입력받고 솔루션 인스턴스를 생성하여 실행한다. + * + * @see #Solution(int) + * 4. 현재 테스트 케이스 번호를 멤버 변수에 저장한다. + * + * @see #run() + * 5. 입력(input), 해결(solve), 출력(print) 로직을 순차적으로 수행한다. + * + * @see #input() + * 6. 100x100 크기의 사다리 판(board) 정보를 입력받는다. + * 7. 입력 과정에서 값이 '2'인 도착 지점의 좌표(goalX, goalY)를 찾아 저장한다. + * + * @see #solve() + * 8. 도착점(goalX, goalY)에서 시작하여 위쪽 방향으로 역추적 시뮬레이션을 시작한다. + * 9. 현재 위치에서 좌/우에 가로축('1')이 있는지 확인한다. + * 9-1. 왼쪽(cx - 1)에 길이 있다면, 왼쪽 길이 끝날 때까지 $x$ 좌표를 감소시킨다. + * 9-2. 왼쪽에 길이 없고 오른쪽(cx + 1)에 길이 있다면, 오른쪽 길이 끝날 때까지 $x$ 좌표를 증가시킨다. + * 10. 좌우 이동이 끝났거나 없다면 위쪽(cy - 1)으로 한 칸 이동한다. + * 11. $y$ 좌표가 0에 도달했을 때의 $x$ 좌표가 시작점이므로 answer에 저장한다. + * + * @see #print() + * 12. 계산된 시작점의 $x$ 좌표를 형식에 맞춰 출력한다. + */ +public class Solution { + static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + static BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out)); + static StringTokenizer line; + + public static void main(String[] args) throws IOException { + // 1. 입출력을 초기화한다. + final int testCount = 10; + + // 2. 총 10개의 테스트 케이스를 반복 처리한다. + for (int testCase = 1; testCase <= testCount; testCase++) { + // 3. 테스트 케이스 번호 읽기 및 솔루션 실행 + reader.readLine(); + new Solution(testCase).run(); + } + } + + // ---------------------------------------------------------- + + private final int BOARD_SIZE = 100; + + private int testCase; + private int answer; + + private char[][] board; + private int goalX; + private int goalY; + + public Solution(int testCase) { + // 4. 멤버 변수를 초기화한다. + this.testCase = testCase; + } + + public void run() throws IOException { + // 5. 입력, 해결, 출력 순서로 실행한다. + input(); + solve(); + print(); + } + + private void input() throws IOException { + // 6. 사다리 판 정보를 저장할 배열 생성 + board = new char[BOARD_SIZE][BOARD_SIZE]; + + for (int y = 0; y < BOARD_SIZE; y++) { + getLine(); + for (int x = 0; x < BOARD_SIZE; x++) { + board[y][x] = line.nextToken().charAt(0); + + // 7. 도착 지점('2')의 좌표를 저장한다. + if (board[y][x] == '2') { + goalX = x; + goalY = y; + } + } + } + } + + private void solve() { + // 8. 도착점에서 역순으로 올라가기 위한 현재 좌표 설정 + int cx = goalX, cy = goalY; + + // 11. y가 0(최상단)에 도달할 때까지 반복 + while (cy > 0) { + boolean check = true; + + // 9-1. 왼쪽 방향으로 이동 가능한지 확인하고 끝까지 이동 + for (; cx > 0 && board[cy][cx - 1] == '1'; cx--, check = false); + + // 9-2. 왼쪽으로 이동하지 않았을 경우에만 오른쪽 방향 확인 및 이동 + for (; check && cx < BOARD_SIZE - 1 && board[cy][cx + 1] == '1'; cx++); + + // 10. 한 층 위로 이동 + cy--; + } + + // 최종 시작점 x 좌표 저장 + answer = cx; + } + + private void print() throws IOException { + // 12. 정답을 화면에 출력한다. + writer.write("#" + testCase + " " + answer + "\n"); + writer.flush(); + } + + // ---------------------------------------------------------- + + private static void getLine() throws IOException { + line = new StringTokenizer(reader.readLine().trim()); + } +} \ No newline at end of file diff --git a/problems/SWEA/p4130/Solution.java b/problems/SWEA/p4130/Solution.java new file mode 100644 index 0000000..631d8f0 --- /dev/null +++ b/problems/SWEA/p4130/Solution.java @@ -0,0 +1,205 @@ +/* + * (4130) [모의 SW 역량테스트] 특이한 자석 + * https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWJfhgr6DTQDFAXc&categoryId=AWJfhgr6DTQDFAXc&categoryType=CODE&problemTitle=4130&orderBy=FIRST_REG_DATETIME&selectCodeLang=ALL&select-1=&pageSize=10&pageIndex=1 + */ + +package swea.p4130; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.util.StringTokenizer; + +/** + * SW Expert Academy - 4130. [모의 SW 역량테스트] 특이한 자석 + * @author YeJun. Jung + * + * @see #main(String[]) + * 1. 입출력을 초기화한다. + * 2. 전체 테스트 케이스 개수를 입력받는다. + * 3. 각 테스트 케이스에 대해 솔루션을 인스턴스화하고 실행한다. + * + * @see #Solution(int) + * 4. 현재 테스트 케이스 번호를 멤버 변수에 저장한다. + * + * @see #run() + * 5. 입력(input), 해결(solve), 출력(print) 로직을 순차적으로 수행한다. + * + * @see #input() + * 6. 회전 명령 횟수를 commandCount에 저장한다. + * 7. 4개 자석의 8개 톱날 정보를 입력받아 gears 배열에 저장한다 (0:N, 1:S). + * + * @see #solve() + * 8. 점수와 기어 회전 상태를 초기화한다. + * 9. 입력된 명령 횟수만큼 반복하며 회전 시뮬레이션을 수행한다. + * 9-1. 회전할 기어 번호와 방향을 입력받아 rotateGears를 호출한다. + * 10. 모든 회전이 끝난 후 최종 점수를 계산한다. + * + * @see #rotateGears(int, char) + * 11. 현재 명령으로 인해 영향을 받는 모든 기어의 회전 방향을 결정한다. + * 11-1. 기준 기어로부터 왼쪽 방향으로 연쇄 회전 여부를 체크한다. + * 11-2. 기준 기어로부터 오른쪽 방향으로 연쇄 회전 여부를 체크한다. + * 11-3. 맞닿은 극이 다를 경우 인접 기어는 반대 방향으로 회전한다. + * 12. 결정된 회전 방향에 따라 각 기어의 12시 방향 인덱스(gearRotates)를 갱신한다. + * + * @see #getDeltaGear(int, int) + * 13. 현재 12시 방향 인덱스를 기준으로 상대적 위치(delta)에 있는 톱날의 극 정보를 반환한다. + * + * @see #updateScore() + * 14. 각 기어의 12시 방향(gearRotates)이 S극인 경우 비트 연산을 통해 점수를 누적한다. + */ +public class Solution { + static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + static BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out)); + static StringTokenizer line; + + public static void main(String[] args) throws IOException { + // 1. 입출력을 초기화한다. + // 2. 전체 테스트 케이스 개수를 입력받는다. + int testCount = Integer.parseInt(reader.readLine().trim()); + + for (int testCase = 1; testCase <= testCount; testCase++) { + // 3. 각 테스트 케이스에 대해 솔루션을 인스턴스화하고 실행한다. + new Solution(testCase).run(); + } + } + + private static void getLine() throws IOException { + line = new StringTokenizer(reader.readLine().trim()); + } + + // -------------------------------------------------------- + + private int testCase; + private int score; + private int commandCount; + private char[][] gears; // 4개 기어에 대해서 N혹은 S값이 저장된다 + private int[] gearRotates; // 현재 빨간색 화살표(12시)가 가리키는 기어의 톱날 Index + + public Solution(int testCase) { + // 4. 현재 테스트 케이스 번호를 멤버 변수에 저장한다. + this.testCase = testCase; + } + + public void run() throws IOException { + // 5. 입력(input), 해결(solve), 출력(print) 로직을 순차적으로 수행한다. + input(); + solve(); + print(); + } + + private void input() throws IOException { + // 6. 회전 명령 횟수를 commandCount에 저장한다. + commandCount = Integer.parseInt(reader.readLine().trim()); + + // 7. 4개 자석의 8개 톱날 정보를 입력받아 gears 배열에 저장한다. + gears = new char[4][8]; // 4개 기어, 8개 톱날 + + for (int index = 0; index < 4; index++) { + getLine(); + for (int count = 0; count < 8; count++) { + gears[index][count] = line.nextToken().charAt(0) == '0' ? 'N' : 'S'; + } + } + } + + private void solve() throws IOException { + // 8. 점수와 기어 회전 상태를 초기화한다. + score = 0; + gearRotates = new int[4]; + + // 9. 입력된 명령 횟수만큼 반복하며 회전 시뮬레이션을 수행한다. + for (int command = 0; command < commandCount; command++) { + getLine(); + // 9-1. 회전할 기어 번호(0-3)와 방향(1:시계, -1:반시계)을 입력받는다. + int gearIndex = Integer.parseInt(line.nextToken()) - 1; + char rotateDir = line.nextToken().charAt(0) == '1' ? '+' : '-'; + + rotateGears(gearIndex, rotateDir); + } + + // 10. 모든 회전이 끝난 후 최종 점수를 계산한다. + updateScore(); + } + + private void rotateGears(int gearIndex, char rotateDir) { + // 11. 현재 명령으로 인해 영향을 받는 모든 기어의 회전 방향을 결정한다. + char[] currentRotates = new char[4]; // 시계(+), 반시계(-), 중립(\0) + currentRotates[gearIndex] = rotateDir; + + // 11-1. 기준 기어로부터 왼쪽 방향으로 연쇄 회전 여부를 체크한다. + for (int gear = gearIndex - 1; gear >= 0; gear--) { + char rightRotateDir = currentRotates[gear + 1]; + if (rightRotateDir == '\0') break; + + char leftSideOfRightGear = getDeltaGear(gear + 1, -2); // 오른쪽 기어의 9시 방향 + char rightSideOfLeftGear = getDeltaGear(gear, 2); // 왼쪽 기어의 3시 방향 + + if (leftSideOfRightGear != rightSideOfLeftGear) { + currentRotates[gear] = rightRotateDir == '+' ? '-' : '+'; + } else break; + } + + // 11-2. 기준 기어로부터 오른쪽 방향으로 연쇄 회전 여부를 체크한다. + for (int gear = gearIndex + 1; gear < 4; gear++) { + char leftRotateDir = currentRotates[gear - 1]; + if (leftRotateDir == '\0') break; + + char rightSideOfLeftGear = getDeltaGear(gear - 1, 2); // 왼쪽 기어의 3시 방향 + char leftSideOfRightGear = getDeltaGear(gear, -2); // 오른쪽 기어의 9시 방향 + + if (rightSideOfLeftGear != leftSideOfRightGear) { + currentRotates[gear] = leftRotateDir == '+' ? '-' : '+'; + } else break; + } + + // 12. 결정된 회전 방향에 따라 각 기어의 12시 방향 인덱스를 갱신한다. + for (int gear = 0; gear < 4; gear++) { + if (currentRotates[gear] != '\0') { + gearRotates[gear] = getRotationIndex(gear, currentRotates[gear]); + } + } + } + + private char getDeltaGear(int gearIndex, int delta) { + // 13. 현재 12시 방향 인덱스를 기준으로 상대적 위치(delta)에 있는 톱날 극 반환 + int x = gearRotates[gearIndex] + delta; + + // 인덱스 보정 (0~7 범위를 벗어날 경우) + if (x < 0) x += 8; + x %= 8; + + return gears[gearIndex][x]; + } + + private int getRotationIndex(int gearIndex, char rotateDir) { + int result = gearRotates[gearIndex]; + + switch (rotateDir) { + case '-': // 반시계 회전: 12시 방향 인덱스가 시계 방향으로 이동 + result = (result + 1) % 8; + break; + case '+': // 시계 회전: 12시 방향 인덱스가 반시계 방향으로 이동 + if (--result < 0) result = 7; + break; + } + + return result; + } + + private void updateScore() { + // 14. 각 기어의 12시 방향이 S극인 경우 점수를 누적한다 (1, 2, 4, 8점). + for (int gear = 0; gear < 4; gear++) { + if (gears[gear][gearRotates[gear]] == 'S') { + score += (1 << gear); + } + } + } + + private void print() throws IOException { + writer.write("#" + testCase + " " + score + "\n"); + writer.flush(); + } +} diff --git a/problems/SWEA/p6808/Solution.java b/problems/SWEA/p6808/Solution.java new file mode 100644 index 0000000..44f4525 --- /dev/null +++ b/problems/SWEA/p6808/Solution.java @@ -0,0 +1,185 @@ +/* + * (6808) 규영이와 인영이의 카드게임 + * https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWgv9va6HnkDFAW0&categoryId=AWgv9va6HnkDFAW0&categoryType=CODE&problemTitle=6808&orderBy=FIRST_REG_DATETIME&selectCodeLang=ALL&select-1=&pageSize=10&pageIndex=1 + */ + +package swea.p6808; + +import java.io.*; +import java.util.*; +import java.util.stream.IntStream; + +/** + * SW Expert Academy - 6808. 규영이와 인영이의 카드게임 + * @author YeJun. Jung + * + * @see #main(String[]) + * 1. 입출력을 초기화한다. + * 2. 전체 테스트 케이스 개수를 입력받는다. + * 3. 각 테스트 케이스에 대해 솔루션을 인스턴스화하고 실행한다. + * + * @see #Solution(int) + * 4. 현재 테스트 케이스 번호를 멤버 변수에 저장한다. + * + * @see #run() + * 5. 입력(input), 해결(solve), 출력(print) 로직을 순차적으로 수행한다. + * + * @see #input() + * 6. 규영이가 내는 카드의 순서(cardOrder)를 입력받는다. + * + * @see #solve() + * 7. 규영이의 카드를 제외한 나머지 카드로 인영이의 카드(myCards)를 구성한다. + * 8. 인영이가 카드를 내는 모든 순열 조합을 생성하기 위해 인덱스 배열(order)을 준비한다. + * 9. nextPermutation을 이용하여 인영이의 카드 순서를 바꾼다. + * 10. 각 게임 라운드마다 점수를 계산한다. + * 10-1. 인영이의 카드 숫자가 크면 인영이의 점수를 합산한다. + * 10-2. 규영이의 카드 숫자가 크면 규영이의 점수를 합산한다(score 변수 차감). + * 11. 최종 점수가 양수면 인영이의 승리(winCount), 음수면 인영이의 패배(loseCount)를 카운트한다. + * + * @see #setupMyCards() + * 12. 비트마스크를 활용하여 1~18번 카드 중 규영이가 사용하지 않은 카드를 myCards에 저장한다. + * + * @see #nextPermutation(int[]) + * 13. 현재 배열의 상태를 사전순으로 나열했을 때의 다음 순열로 변환한다. + * + * @see #print() + * 14. 규영이의 패배 횟수(인영의 승리)와 승리 횟수(인영의 패배)를 출력한다. + */ +public class Solution { + static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + static BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out)); + static StringTokenizer line; + + public static void main(String[] args) throws IOException { + // 1. 입출력을 초기화한다. + // 2. 전체 테스트 케이스 개수를 입력받는다. + int testCount = Integer.parseInt(reader.readLine().trim()); + + for (int testCase = 1; testCase <= testCount; testCase++) { + // 3. 각 테스트 케이스에 대해 솔루션을 실행한다. + new Solution(testCase).run(); + } + } + + // ---------------------------------------------------------- + + private static final int CARD_LEN = 9; + + private int testCase; + private int[] cardOrder; // 규영이의 카드 순서 + private int[] myCards; // 인영이가 가진 카드 목록 + + private int loseCount; // 인영이가 지는 횟수 (규영이가 이기는 횟수) + private int winCount; // 인영이가 이기는 횟수 (규영이가 지는 횟수) + + public Solution(int testCase) { + // 4. 현재 테스트 케이스 번호를 멤버 변수에 저장한다. + this.testCase = testCase; + } + + public void run() throws IOException { + // 5. 입력, 해결, 출력 순서로 실행한다. + input(); + solve(); + print(); + } + + public void input() throws IOException { + // 6. 규영이가 내는 카드의 순서를 입력받는다. + cardOrder = new int[CARD_LEN]; + + getLine(); + for (int index = 0; index < CARD_LEN; index++) { + cardOrder[index] = Integer.parseInt(line.nextToken()); + } + } + + public void solve() { + winCount = 0; + loseCount = 0; + + // 7. 인영이의 카드 목록을 설정한다. + setupMyCards(); + + // 8. 모든 순열을 탐색하기 위한 인덱스 배열 준비 + int[] order = IntStream.rangeClosed(0, CARD_LEN - 1).toArray(); + + // 9. nextPermutation을 사용하여 모든 가능한 인영이의 카드 제출 순서를 확인한다. + do { + int score = 0; + int currentSum; + + // 10. 한 게임(9라운드) 진행 + for (int index = 0; index < CARD_LEN; index++) { + currentSum = cardOrder[index] + myCards[order[index]]; + + if (cardOrder[index] < myCards[order[index]]) { + // 10-1. 인영이의 카드 숫자가 더 큰 경우 점수 합산 + score += currentSum; + } else if (cardOrder[index] > myCards[order[index]]) { + // 10-2. 규영이의 카드 숫자가 더 큰 경우 (음수 처리로 규영이 점수 관리) + score -= currentSum; + } + } + + // 11. 게임 결과 카운트 + if (score > 0) { + winCount++; // 인영 승 + } else if (score < 0) { + loseCount++; // 인영 패 (규영 승) + } + } while (nextPermutation(order)); + } + + private void setupMyCards() { + // 12. 비트마스크를 활용하여 인영이의 카드를 할당한다. + myCards = new int[CARD_LEN]; + + int mask = 0; + for (int card : cardOrder) mask |= (1 << card); + + for (int count = 1, index = 0; index < CARD_LEN; count++) { + if ((mask & (1 << count)) != 0) continue; + myCards[index++] = count; + } + } + + public void print() throws IOException { + // 14. 규영이의 승리 횟수와 패배 횟수를 형식에 맞춰 출력한다. + // 주의: 문제 요구사항에 따라 규영이 기준(loseCount, winCount 순서)으로 출력 + writer.write("#" + testCase + " " + loseCount + " " + winCount + "\n"); + writer.flush(); + } + + // ---------------------------------------------------------- + + private static void getLine() throws IOException { + line = new StringTokenizer(reader.readLine().trim()); + } + + /** + * 13. 다음 순열을 찾는 알고리즘 (Next Permutation) + */ + private static boolean nextPermutation(int[] x) { + int n = x.length - 1, a = n, b = n; + // 1. 뒤에서부터 x[i-1] < x[i]인 지점(a)을 찾는다. + while (a > 0 && x[a - 1] >= x[a]) a--; + if (a == 0) return false; + + // 2. 다시 뒤에서부터 x[a-1]보다 큰 x[b]를 찾는다. + while (x[a - 1] >= x[b]) b--; + + // 3. x[a-1]과 x[b]를 교환하고 a 이후의 배열을 뒤집는다. + swap(x, a - 1, b); + reverse(x, a, n); + return true; + } + + private static void reverse(int[] x, int a, int b) { + while (a < b) swap(x, a++, b--); + } + + private static void swap(int[] x, int a, int b) { + int t = x[a]; x[a] = x[b]; x[b] = t; + } +} \ No newline at end of file diff --git a/problems/baekjoon/p1325/Main.java b/problems/baekjoon/p1325/Main.java new file mode 100644 index 0000000..ec44329 --- /dev/null +++ b/problems/baekjoon/p1325/Main.java @@ -0,0 +1,154 @@ +/* + * (1325) 효율적인 해킹 + * https://www.acmicpc.net/problem/1325 + */ + +package baekjoon.p1325; + +import java.io.*; +import java.util.*; + +/** + * 백준 - 1325. 효율적인 해킹 + * @author YeJun, Jung + * + * @see #main(String[]) + * 1. 메인 실행부에서 Main 인스턴스를 생성하고 run을 호출한다. + * + * @see #run() + * 2. 입력(input), 해결(solve), 출력(print) 로직을 순차적으로 수행한다. + * + * @see #input() + * 3. 컴퓨터 개수(comCount)와 신뢰 관계 개수(inputLines)를 입력받는다. + * 4. 인접 리스트 구조의 그래프를 초기화한다. + * 5. 신뢰 관계(A가 B를 신뢰한다)를 입력받아 역방향(B -> A)으로 간선을 저장한다. + * (B를 해킹했을 때 전파되는 경로를 추적하기 위함) + * + * @see #solve() + * 6. 모든 정점에 대해 각각 해킹 가능한 컴퓨터 수를 계산한다. + * 7. graphMembers(BFS)를 호출하여 해당 정점에서 도달 가능한 노드 리스트를 반환받는다. + * 8. 현재까지의 최대 방문 수(maxVisited)와 비교하여 정답 리스트(answer)를 관리한다. + * 8-1. 더 큰 값이 나오면 기존 리스트를 비우고(clear) 갱신한다. + * 8-2. 같은 값이 나오면 리스트에 추가한다. + * + * @see #graphMembers(int) + * 9. BFS 알고리즘을 사용하여 특정 노드에서 접근 가능한 모든 노드를 탐색한다. + * 10. 방문 여부를 체크(visited)하며 큐(Queue)에 자식 노드들을 삽입한다. + * 11. 탐색이 완료된 모든 노드 정보를 리스트에 담아 반환한다. + * + * @see #print() + * 12. 정답 리스트를 오름차순으로 정렬한 뒤 공백으로 구분하여 출력한다. + */ +public class Main { + static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + static BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out)); + static StringTokenizer line; + + public static void main(String[] args) throws IOException { + // 1. 메인 실행부 실행 + new Main().run(); + } + + // ---------------------------------------------------------- + + private int comCount; + private int inputLines; + List> graph; + private List answer; + + public Main() { } + + public void run() throws IOException { + // 2. 실행 프로세스 제어 + input(); + solve(); + print(); + } + + private void input() throws IOException { + // 3. 컴퓨터 수와 입력 라인 수 초기화 + getLine(); + comCount = Integer.parseInt(line.nextToken()); + inputLines = Integer.parseInt(line.nextToken()); + + // 4. 인접 리스트 생성 + graph = new ArrayList<>(); + for (int count = 0; count < comCount + 1; count++) graph.add(new ArrayList<>()); + + // 5. 신뢰 관계를 역방향 그래프로 저장 (전파 경로 추적 최적화) + for (int lineCount = 0; lineCount < inputLines; lineCount++) { + getLine(); + int com0 = Integer.parseInt(line.nextToken()); // A (신뢰하는 쪽) + int com1 = Integer.parseInt(line.nextToken()); // B (신뢰받는 쪽) + + // 자기 자신을 신뢰하는 경우가 아니라면 B -> A 연결 + if (com0 != com1) graph.get(com1).add(com0); + } + } + + private void solve() { + // 6. 결과 저장소 및 최대 방문 수 초기화 + answer = new ArrayList<>(); + int maxVisited = 0; + + for (int current = 1; current <= comCount; current++) { + // 7. 각 컴퓨터를 시작점으로 BFS 수행 + List result = graphMembers(current); + final int size = result.size(); + + // 8. 최대 해킹 가능 수 갱신 로직 + if (size < maxVisited) continue; + if (size > maxVisited) { + answer.clear(); + maxVisited = size; + } + answer.add(current); + } + } + + /** + * 9. 너비 우선 탐색(BFS)을 통한 도달 가능 노드 탐색 + */ + private List graphMembers(int nodeIndex) { + List result = new ArrayList<>(); + ArrayDeque queue = new ArrayDeque<>(); + boolean[] visited = new boolean[comCount + 1]; + + // 10. 시작 노드 방문 처리 + queue.offer(nodeIndex); + visited[nodeIndex] = true; + + while (!queue.isEmpty()) { + Integer top = queue.poll(); + result.add(top); + + // 연결된 신뢰 관계를 따라 해킹 전파 확인 + for (int child : graph.get(top)) { + if (visited[child]) continue; + visited[child] = true; + + queue.offer(child); + } + } + + // 11. 도달 가능한 모든 컴퓨터 리스트 반환 + return result; + } + + private void print() throws IOException { + // 12. 문제 조건에 따라 오름차순 정렬 후 출력 + Collections.sort(answer); + + for (Integer child : answer) { + writer.write(child + " "); + } + writer.write("\n"); + writer.flush(); + } + + // ---------------------------------------------------------- + + private static void getLine() throws IOException { + line = new StringTokenizer(reader.readLine().trim()); + } +} \ No newline at end of file diff --git a/problems/baekjoon/p15649/Main.java b/problems/baekjoon/p15649/Main.java new file mode 100644 index 0000000..31a7aee --- /dev/null +++ b/problems/baekjoon/p15649/Main.java @@ -0,0 +1,119 @@ +/* + * (15649) N과 M (1) + * https://www.acmicpc.net/problem/15649 + */ + +package baekjoon.p15649; + +import java.io.*; +import java.util.*; +import java.util.stream.IntStream; + +/** + * 백준 - 15649. N과 M (1) + * @author YeJun, Jung + * + * @see #main(String[]) + * 1. 입출력을 초기화한다. + * 2. N(전체 수의 범위)과 M(고를 수의 개수)을 입력받는다. + * 3. 조합을 선택하기 위한 select 배열을 생성하고 상위 M개를 1로 채운다. + * 4. prevPermutation을 활용하여 N개 중 M개를 뽑는 조합 시뮬레이션을 수행한다. + * 5. 선택된 숫자들을 buffer 배열에 담는다. + * 6. buffer에 담긴 숫자들을 다시 순열로 나열하기 위해 order 인덱스 배열을 생성한다. + * 7. prevPermutation을 활용하여 선택된 M개의 숫자로 만들 수 있는 모든 순열을 생성한다. + * 8. 생성된 각 순열을 StringBuilder에 담아 result 리스트에 저장한다. + * 9. 모든 조합과 순열 생성이 끝나면 result 리스트를 사전순으로 정렬한다. + * 10. 정답 리스트를 화면에 출력한다. + * + * @see #prevPermutation(int[]) + * 11. 현재 배열의 상태를 사전순의 이전 단계 순열로 변환한다. + * 11-1. 뒤에서부터 인접한 두 원소가 오름차순(x[a-1] > x[a])인 지점을 찾는다. + * 11-2. 다시 뒤에서부터 x[a-1]보다 작은 원소를 찾아 교환(swap)한다. + * 11-3. 지점 a 이후의 배열을 뒤집어(reverse) 이전 순열을 완성한다. + */ +public class Main { + static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + static BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out)); + static StringTokenizer line; + + public static void main(String[] args) throws IOException { + // 1. 입출력을 초기화한다. + getLine(); + + // 2. N과 M을 입력받는다. + int N = Integer.parseInt(line.nextToken()); + int M = Integer.parseInt(line.nextToken()); + + // 3. 조합 선택용 배열 (1인 위치의 인덱스를 숫자로 사용) + int[] select = new int[N]; + Arrays.fill(select, 0, M, 1); + + List result = new ArrayList<>(); + + // 4. 조합(Combination) 생성 루프 + do { + // 5. 현재 조합에서 선택된 숫자들을 buffer에 저장 + int[] buffer = new int[M]; + for (int num = 0, index = 0; num < N; num++) { + if (select[num] == 1) buffer[index++] = num + 1; + } + + // 6. 선택된 숫자들 내에서 순열을 만들기 위한 인덱스 배열 + int[] order = IntStream.rangeClosed(0, M - 1).toArray(); + reverse(order, 0, M - 1); // 내림차순 정렬 상태에서 prevPermutation 시작 + + // 7. 순열(Permutation) 생성 루프 + do { + StringBuilder output = new StringBuilder(); + // 8. 현재 순열 순서대로 숫자를 이어붙여 결과 리스트에 추가 + for (int index = 0; index < M; index++) { + output.append(buffer[order[index]] + " "); + } + result.add(output.toString()); + } while (prevPermutation(order)); // 11. 이전 순열이 존재하면 반복 + + } while (prevPermutation(select)); + + // 9. 모든 결과를 사전순으로 정렬한다. + Collections.sort(result); + + // 10. 정답 배열 내용을 화면에 출력한다. + for (String line : result) { + writer.write(line); + writer.write("\n"); + } + writer.flush(); + } + + // ---------------------------------------------------------- + + private static void getLine() throws IOException { + line = new StringTokenizer(reader.readLine().trim()); + } + + /** + * 11. 사전순의 이전 순열을 생성하는 메서드 + */ + private static boolean prevPermutation(int[] x) { + int n = x.length - 1, a = n, b = n; + // 11-1. 뒤에서부터 하강 지점 탐색 + while (a > 0 && x[a - 1] <= x[a]) a--; + if (a == 0) return false; + + // 11-2. 교환할 위치 탐색 + while (x[a - 1] <= x[b]) b--; + + // 11-3. 교환 및 반전 + swap(x, a - 1, b); + reverse(x, a, n); + return true; + } + + private static void reverse(int[] x, int a, int b) { + while (a < b) swap(x, a++, b--); + } + + private static void swap(int[] x, int a, int b) { + int t = x[a]; x[a] = x[b]; x[b] = t; + } +} \ No newline at end of file diff --git a/problems/baekjoon/p5567/Main.java b/problems/baekjoon/p5567/Main.java new file mode 100644 index 0000000..683dad5 --- /dev/null +++ b/problems/baekjoon/p5567/Main.java @@ -0,0 +1,121 @@ +/* + * (5567) 결혼식 + * https://www.acmicpc.net/problem/5567 + */ + +package baekjoon.p5567; + +import java.io.*; +import java.util.*; + +/** + * 백준 - 5567. 결혼식 + * @author YeJun, Jung + * + * @see #main(String[]) + * 1. 메인 실행부에서 Main 인스턴스를 생성하고 run을 호출한다. + * + * @see #run() + * 2. 입력(input), 해결(solve), 출력(print) 로직을 순차적으로 수행한다. + * + * @see #input() + * 3. 동기의 수(nodeCount)와 리스트의 길이(inputLines)를 입력받는다. + * 4. 인접 리스트 구조의 그래프를 초기화한다. + * 5. 친구 관계를 입력받아 양방향 그래프로 저장한다 (a-b는 서로 친구). + * + * @see #solve() + * 6. 상근이(1번 노드)의 직접적인 친구와 친구의 친구를 찾기 위한 탐색을 시작한다. + * 7. 방문 여부를 체크할 checked 배열을 초기화하고 상근이 본인(1번)을 방문 처리한다. + * 8. 상근이의 인접 리스트를 순회하며 직접적인 친구(Depth 1)를 friends 리스트에 담는다. + * 9. 찾은 직접적인 친구들의 인접 리스트를 다시 순회하며 '친구의 친구'(Depth 2)를 탐색한다. + * 10. 이미 방문한 노드(상근이 본인 또는 중복된 친구)를 제외하고 새로운 사람을 발견할 때마다 answer를 증가시킨다. + * + * @see #print() + * 11. 최종적으로 계산된 초대 인원(answer)을 출력한다. + */ +public class Main { + static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + static BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out)); + static StringTokenizer line; + + public static void main(String[] args) throws IOException { + // 1. 인스턴스 생성 및 실행 + new Main().run(); + } + + // ---------------------------------------------------------- + + private int answer; + private int nodeCount; + private List> graph; + + public Main() { } + + public void run() throws IOException { + // 2. 전체 프로세스 제어 + input(); + solve(); + print(); + } + + private void input() throws IOException { + // 3. 동기의 수와 관계의 수 입력 + nodeCount = Integer.parseInt(reader.readLine().trim()); + int inputLines = Integer.parseInt(reader.readLine().trim()); + + // 4. 인접 리스트 초기화 + graph = new ArrayList<>(); + for (int count = 0; count < nodeCount + 1; count++) graph.add(new ArrayList<>()); + + // 5. 양방향 친구 관계 구축 + for (int lineCount = 0; lineCount < inputLines; lineCount++) { + getLine(); + int a = Integer.parseInt(line.nextToken()); + int b = Integer.parseInt(line.nextToken()); + + graph.get(a).add(b); + graph.get(b).add(a); + } + } + + private void solve() { + List friends = new ArrayList<>(); + boolean[] checked = new boolean[501]; // 최대 동기 수 500명 + + // 7. 상근이 본인(1번)은 초대 인원에서 제외하기 위해 미리 방문 처리 + checked[1] = true; + + // 8. 상근이의 직접적인 친구(Depth 1) 찾기 + for (Integer node : graph.get(1)) { + if (checked[node]) continue; + checked[node] = true; + + friends.add(node); + } + + // 직접적인 친구 수만큼 정답 초기화 + answer = friends.size(); + + // 9. 친구의 친구(Depth 2) 탐색 + for (Integer friend : friends) { + for (Integer node : graph.get(friend)) { + // 10. 아직 초대 리스트에 없는 사람만 추가 + if (checked[node]) continue; + checked[node] = true; + answer++; + } + } + } + + private void print() throws IOException { + // 11. 최종 결과 출력 + writer.write(answer + "\n"); + writer.flush(); + } + + // ---------------------------------------------------------- + + private static void getLine() throws IOException { + line = new StringTokenizer(reader.readLine().trim()); + } +} \ No newline at end of file