diff --git a/problems/SWEA/p1868/Solution.java b/problems/SWEA/p1868/Solution.java new file mode 100644 index 0000000..cb45d56 --- /dev/null +++ b/problems/SWEA/p1868/Solution.java @@ -0,0 +1,181 @@ +/* + * (1868) 파핑파핑 지뢰찾기 + * https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV5LwsHaD1MDFAXc&categoryId=AV5LwsHaD1MDFAXc&categoryType=CODE&problemTitle=1868&orderBy=FIRST_REG_DATETIME&selectCodeLang=ALL&select-1=&pageSize=10&pageIndex=1 + */ + +import java.io.*; +import java.util.*; + +/** + * SW Expert Academy - 파핑파핑 지뢰찾기 + * @author YeJun, Jung + * + * [분석] + * - 지뢰찾기 게임과 규칙은 동일하다. + * - 최소한의 클릭으로 지뢰가 없는 칸들을 모두 여는 방법을 찾아야 한다. + * + * [전략] + * - 각 칸은 ID를 가지고 있다. + * - 각 ID에 대해서 부모 노드의 ID를 보관하는 배열 parentArr가 있다. + * - 처음에 parentArr는 자기자신을 가르키도록 초기화 한다. + * - 각 칸(ID)에 대해서 DFS으로 칸을 열어본다. + * - 열어본 칸에 대해서는 ID로 기록을 한다. + * - 칸을 열때 다른 ID가 기록되어 있다면 해당 칸의 ID와 현재 ID를 Union 한다. + * - parentArr에 있는 ID 종류의 개수가 정답이 된다. + */ +public class Solution { + static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + static StringBuilder output = new StringBuilder(); + static StringTokenizer input; + + // ---------------------------------------------------------- + + public static void main(String[] args) throws IOException { + final int testCount = nextInt(); + + for (int testCase = 1; testCase <= testCount; testCase++) { + new Solution(testCase).run(); + } + + System.out.print(output.toString()); + } + + // ---------------------------------------------------------- + + static final int[] DIR_X = { -1, 1, 0, 0, 1, 1, -1, -1 }; + static final int[] DIR_Y = { 0, 0, -1, 1, 1, -1, 1, -1 }; + static final int DIR_LEN = 8; + + int testCase; + int answer; + int boardSize; + int[][] board; + + int[] parentArr; + + public Solution(int testCase) { this.testCase = testCase; } + public void run() throws IOException { input(); solve(); print(); } + + private void input() throws IOException { + char[] buf; + + boardSize = nextInt(); + board = new int[boardSize][boardSize]; + + for (int y = 0; y < boardSize; y++) { + buf = next().toCharArray(); + + for (int x = 0; x < boardSize; x++) { + if (buf[x] == '.') continue; + + board[y][x] = -1; + } + } + } + + private void solve() { + answer = 0; + + makeParentArr(); + + for (int y = 0; y < boardSize; y++) { + for (int x = 0; x < boardSize; x++) { + int id = (y * boardSize) + x + 1; + + if (board[y][x] != 0) { + parentArr[id] = 0; + continue; + } + + board[y][x] = id; + openTile(x, y, id); + } + } + + updateAnswer(); + } + + private void makeParentArr() { + final int N = boardSize * boardSize + 1; + parentArr = new int[N]; + + for (int idx = 0; idx < N; idx++) { + parentArr[idx] = idx; + } + } + + private int findParent(int idx) { + if (parentArr[idx] == idx) return idx; + return findParent(parentArr[idx]); + } + + private void unionParent(int a, int b) { + int pa = findParent(a); + int pb = findParent(b); + if (pa != pb) parentArr[pb] = pa; + } + + private void openTile(int x, int y, int id) { + int cnt = 0; + + for (int dir = 0; dir < DIR_LEN; dir++) { + int nx = x + DIR_X[dir]; + int ny = y + DIR_Y[dir]; + + if (!isInsideBoard(nx, ny)) continue; + if (board[ny][nx] == -1) cnt++; + } + + if (cnt != 0) return; + + for (int dir = 0; dir < DIR_LEN; dir++) { + int nx = x + DIR_X[dir]; + int ny = y + DIR_Y[dir]; + + if (!isInsideBoard(nx, ny) || board[ny][nx] == -1) continue; + + if (board[ny][nx] != 0) { + unionParent(id, board[ny][nx]); + continue; + } + + board[ny][nx] = id; + openTile(nx, ny, id); + } + } + + private boolean isInsideBoard(int x, int y) { + return x >= 0 && x < boardSize && y >= 0 && y < boardSize; + } + + private void updateAnswer() { + Set set = new HashSet<>(); + for (int idx = 1; idx < parentArr.length; idx++) { + if (parentArr[idx] == 0) continue; + set.add(parentArr[idx]); + } + + answer = set.size(); + } + + private void print() { + output + .append('#') + .append(testCase) + .append(' ') + .append(answer) + .append('\n'); + } + + // ---------------------------------------------------------- + + static String next() throws IOException { + if (input == null || !input.hasMoreTokens()) + input = new StringTokenizer(reader.readLine().trim()); + return input.nextToken(); + } + + static int nextInt() throws IOException { + return Integer.parseInt(next()); + } +} diff --git a/problems/SWEA/p3289/Solution.java b/problems/SWEA/p3289/Solution.java new file mode 100644 index 0000000..d5f7e9c --- /dev/null +++ b/problems/SWEA/p3289/Solution.java @@ -0,0 +1,112 @@ +/* + * (3289) 서로소 집합 + * https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWBJKA6qr2oDFAWr&categoryId=AWBJKA6qr2oDFAWr&categoryType=CODE&problemTitle=3289&orderBy=FIRST_REG_DATETIME&selectCodeLang=ALL&select-1=&pageSize=10&pageIndex=1 + */ + +import java.io.*; +import java.util.*; + +/** + * SW Expert Academy - 서로소 집합 + * @author YeJun, Jung + * + * [분석] + * - 런타임에 합집합 연산과 같은 집합에 속해있는지 확인하는 연산을 빠르게 수행해야 하는 문제이다. + * + * [전략] + * - Union-Find 알고리즘 적용 + * - Path compression 최적화 사용 + */ +public class Solution { + static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + static StringBuilder output = new StringBuilder(); + static StringTokenizer input; + + // ---------------------------------------------------------- + + public static void main(String[] args) throws IOException { + final int testCount = nextInt(); + + for (int testCase = 1; testCase <= testCount; testCase++) { + new Solution(testCase).run(); + } + + System.out.print(output.toString()); + } + + // ---------------------------------------------------------- + + int testCase; + int answer; + int nodeLen; + int cmdLen; + int[] parentArr; + + public Solution(int testCase) { this.testCase = testCase; } + public void run() throws IOException { input(); solve(); print(); } + + private void input() throws IOException { + nodeLen = nextInt(); + cmdLen = nextInt(); + } + + private void solve() throws IOException { + output + .append('#') + .append(testCase) + .append(' '); + + parentArr = new int[nodeLen + 1]; + for (int idx = 1; idx <= nodeLen; idx++) { + parentArr[idx] = idx; + } + + int cmd, arg0, arg1; + + for (int cnt = 0; cnt < cmdLen; cnt++) { + cmd = nextInt(); + arg0 = nextInt(); + arg1 = nextInt(); + + if (cmd == 0) { + // union + unionParent(arg0, arg1); + } else { + // find + output.append(checkParent(arg0, arg1) ? '1' : '0'); + } + } + } + + private boolean checkParent(int a, int b) { + return findParent(a) == findParent(b); + } + + private void unionParent(int a, int b) { + int pa = findParent(a); + int pb = findParent(b); + + if (pa != pb) parentArr[pb] = pa; + } + + private int findParent(int node) { + if (parentArr[node] == node) return node; + return parentArr[node] = findParent(parentArr[node]); + } + + private void print() { + output.append('\n'); + } + + // ---------------------------------------------------------- + + static String next() throws IOException { + if (input == null || !input.hasMoreTokens()) + input = new StringTokenizer(reader.readLine().trim()); + return input.nextToken(); + } + + static int nextInt() throws IOException { + return Integer.parseInt(next()); + } +} diff --git a/problems/SWEA/p7465/Solution.java b/problems/SWEA/p7465/Solution.java new file mode 100644 index 0000000..900d691 --- /dev/null +++ b/problems/SWEA/p7465/Solution.java @@ -0,0 +1,114 @@ +/* + * (7465) 창용 마을 무리의 개수 + * https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWngfZVa9XwDFAQU&categoryId=AWngfZVa9XwDFAQU&categoryType=CODE&problemTitle=7465&orderBy=FIRST_REG_DATETIME&selectCodeLang=ALL&select-1=&pageSize=10&pageIndex=1 + */ + +import java.io.*; +import java.util.*; + +/** + * SW Expert Academy - 창용 마을 무리의 개수 + * @author YeJun, Jung + * + * [전략] + * - Union-Find 알고리즘 적용 + * - Path compression 최적화 사용 + */ +public class Solution { + static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + static StringBuilder output = new StringBuilder(); + static StringTokenizer input; + + // ---------------------------------------------------------- + + public static void main(String[] args) throws IOException { + final int testCount = nextInt(); + + for (int testCase = 1; testCase <= testCount; testCase++) { + new Solution(testCase).run(); + } + + System.out.print(output.toString()); + } + + // ---------------------------------------------------------- + + int testCase; + int answer; + int nodeLen; + int edgeLen; + int[] parentArr; + + public Solution(int testCase) { this.testCase = testCase; } + public void run() throws IOException { input(); solve(); print(); } + + private void input() throws IOException { + int a, b; + + nodeLen = nextInt(); + edgeLen = nextInt(); + + makeParentArr(); + + for (int edge = 0; edge < edgeLen; edge++) { + a = nextInt(); + b = nextInt(); + + unionParent(a, b); + } + } + + private void makeParentArr() { + parentArr = new int[nodeLen + 1]; + for (int idx = 1; idx <= nodeLen; idx++) { + parentArr[idx] = idx; + } + } + + private void unionParent(int a, int b) { + int pa = findParent(a); + int pb = findParent(b); + + if (pa != pb) parentArr[pb] = pa; + } + + private int findParent(int x) { + if (parentArr[x] == x) return x; + return parentArr[x] = findParent(parentArr[x]); + } + + private void solve() { + answer = cntGroup(); + } + + private int cntGroup() { + Set set = new HashSet<>(); + + for (int idx = 1; idx <= nodeLen; idx++) { + set.add(findParent(idx)); + } + + return set.size(); + } + + private void print() { + output + .append('#') + .append(testCase) + .append(' ') + .append(answer) + .append('\n'); + } + + // ---------------------------------------------------------- + + static String next() throws IOException { + if (input == null || !input.hasMoreTokens()) + input = new StringTokenizer(reader.readLine().trim()); + return input.nextToken(); + } + + static int nextInt() throws IOException { + return Integer.parseInt(next()); + } +} diff --git a/problems/baekjoon/p13023/Main.java b/problems/baekjoon/p13023/Main.java new file mode 100644 index 0000000..e9130af --- /dev/null +++ b/problems/baekjoon/p13023/Main.java @@ -0,0 +1,111 @@ +/* + * (13023) ABCDE + * https://www.acmicpc.net/problem/13023 + */ + +import java.io.*; +import java.util.*; + +/** + * Baekjoon - ABCDE + * @author YeJun, Jung + * + * [분석] + * - A -> B -> C -> D -> E 관계가 그래프 안에 존재하는지 파악하는 문제이다. + * + * [전략] + * - 인접리스트로 그래프를 저장한다. + * - 모든 정점에서 출발하는 DFS를 통해서 깊이가 4이상 되는지 파악한다. + * - 깊이가 4가 되면 탐색을 조기 종료하여 최적화 한다. + */ +public class Main { + static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + static StringBuilder output = new StringBuilder(); + static StringTokenizer input; + + // ---------------------------------------------------------- + + public static void main(String[] args) throws IOException { + new Main().run(); + System.out.print(output.toString()); + } + + // ---------------------------------------------------------- + + int answer; + int nodeLen; + int edgeLen; + List> graph; + boolean[] visited; + + public void run() throws IOException { input(); solve(); print(); } + + private void input() throws IOException { + int a, b; + + nodeLen = nextInt(); + edgeLen = nextInt(); + + graph = new ArrayList<>(nodeLen); + for (int idx = 0; idx < nodeLen; idx++) { + graph.add(new ArrayList<>()); + } + + for (int edge = 0; edge < edgeLen; edge++) { + a = nextInt(); + b = nextInt(); + + graph.get(a).add(b); + graph.get(b).add(a); + } + } + + private void solve() { + visited = new boolean[nodeLen]; + answer = 0; + + for (int node = 0; node < nodeLen; node++) { + visited[node] = true; + dfs(node, 0); + visited[node] = false; + + if (answer == 1) return; + } + } + + private void dfs(int node, int cnt) { + if (answer == 1) return; + if (cnt == 4) { + answer = 1; + return; + } + + for (int child : graph.get(node)) { + if (visited[child]) continue; + + visited[child] = true; + dfs(child, cnt + 1); + visited[child] = false; + + if (answer == 1) return; + } + } + + private void print() { + output + .append(answer) + .append('\n'); + } + + // ---------------------------------------------------------- + + static String next() throws IOException { + if (input == null || !input.hasMoreTokens()) + input = new StringTokenizer(reader.readLine().trim()); + return input.nextToken(); + } + + static int nextInt() throws IOException { + return Integer.parseInt(next()); + } +} diff --git a/problems/baekjoon/p15683/Main.java b/problems/baekjoon/p15683/Main.java new file mode 100644 index 0000000..9d605bf --- /dev/null +++ b/problems/baekjoon/p15683/Main.java @@ -0,0 +1,164 @@ +/* + * (15683) 감시 + * https://www.acmicpc.net/problem/15683 + */ + +import java.io.*; +import java.util.*; + +/** + * Baekjoon - 감시 + * @author YeJun, Jung + * + * [분석] + * - CCTV는 5가지 종류가 있으며, 각각 감시할 수 있는 방향이 다르다. + * - CCTV는 90도 회전이 가능하다. + * - CCTV는 벽으로 가로막히지 않는한 바라보는 방향으로 끝까지 감시할 수 있다. + * + * [전략] + * - 각 CCTV의 방향을 바꿔가면서 DFS 탐색한다. + * - 모든 CCTV의 방향이 결정되면 CCTV가 감시하지 않는 사각지대의 크기를 센다. + * - 사각지대가 가장 작아지는 CCTV 방향의 조합을 찾는다. + */ +public class Main { + static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + static StringBuilder output = new StringBuilder(); + static StringTokenizer input; + + // ---------------------------------------------------------- + + public static void main(String[] args) throws IOException { + new Main().run(); + System.out.print(output.toString()); + } + + // ---------------------------------------------------------- + + static final int TILE_WALL = 6; + + static final int[] DIR_X = { 0, 1, 0, -1 }; // UP, RIGHT, DOWN, LEFT + static final int[] DIR_Y = { -1, 0, 1, 0 }; // UP, RIGHT, DOWN, LEFT + + // 비트 마스크를 활용하여 델타배열(DIR_X, DIR_Y)의 인덱스를 기록한다. + static final int[] CAM_DIR = { + 0b0000, + 0b0100, // 1번 + 0b0101, // 2번 + 0b1100, // 3번 + 0b1101, // 4번 + 0b1111, // 5번 + }; + + int answer; + int height; + int width; + int[][] board; + List camList; + int camLen; + + public void run() throws IOException { input(); solve(); print(); } + + private void input() throws IOException { + int buf; + camList = new ArrayList<>(8); + + height = nextInt(); + width = nextInt(); + board = new int[height][width]; + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + buf = board[y][x] = nextInt(); + + // CCTV는 따로 모아 리스트에 추가한다. + if (buf > 0 && buf < TILE_WALL) { + camList.add(new Cam(x, y, buf)); + } + } + } + + camLen = camList.size(); + } + + private void solve() { + // DFS 탐색 시작 + answer = dfs(0); + } + + private int dfs(int idx) { + if (idx == camLen) return cntTile(); + + Cam cam = camList.get(idx); + int key = (cam.y * height) + cam.x + 10; + int result = Integer.MAX_VALUE; + + for (int rotate = 0; rotate < 4; rotate++) { + fillCam(cam, rotate, key, 0); + result = Math.min(result, dfs(idx + 1)); + fillCam(cam, rotate, 0, key); + } + + return result; + } + + private void fillCam(Cam cam, int rotate, int fg, int bg) { + for (int vec = 0; vec < 4; vec++) { + if ((CAM_DIR[cam.type] & (1 << (3 - vec))) == 0) continue; + + int dir = (vec + rotate) % 4; + int nx = cam.x + DIR_X[dir]; + int ny = cam.y + DIR_Y[dir]; + + while (isInsideBoard(nx, ny) && board[ny][nx] != TILE_WALL) { + if (board[ny][nx] == bg) board[ny][nx] = fg; + + nx += DIR_X[dir]; + ny += DIR_Y[dir]; + } + } + } + + private int cntTile() { + int cnt = 0; + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + if (board[y][x] == 0) cnt++; + } + } + + return cnt; + } + + private boolean isInsideBoard(int x, int y) { + return x >= 0 && x < width && y >= 0 && y < height; + } + + private void print() { + output.append(answer).append('\n'); + } + + // ---------------------------------------------------------- + + static class Cam { + int x, y, type; + + public Cam(int x, int y, int type) { + this.x = x; + this.y = y; + this.type = type; + } + } + + // ---------------------------------------------------------- + + static String next() throws IOException { + if (input == null || !input.hasMoreTokens()) + input = new StringTokenizer(reader.readLine().trim()); + return input.nextToken(); + } + + static int nextInt() throws IOException { + return Integer.parseInt(next()); + } +}