diff --git "a/BOJ/1000-5000\353\262\210/DH_1765.java" "b/BOJ/1000-5000\353\262\210/DH_1765.java" new file mode 100644 index 00000000..3992c04c --- /dev/null +++ "b/BOJ/1000-5000\353\262\210/DH_1765.java" @@ -0,0 +1,83 @@ +import java.io.*; +import java.util.*; + +/* + * 닭싸움 팀 정하기 + */ + +public class DH_1765 { + static class Node { + int e; + boolean isFriend; + + public Node(int e, boolean isFriend) { + this.e = e; + this.isFriend = isFriend; + } + } + static boolean[] check; + static ArrayList adj[]; + static int groupCnt; + + public static void main(String[] args) throws Exception { + initInput(); + solution(); + } + + static void solution() { + for(int i = 1; i < check.length; i++) { + if(check[i]) continue; + groupCnt += 1; + dfs(i); + } + + System.out.println(groupCnt); + } + + static void dfs(int node) { + check[node] = true; + + for(Node next: adj[node]) { + // 현재 사람의 바로 옆 사람이 친구라면 같은 팀을 할 수 있음 + if(next.isFriend) { + + if(check[next.e]) continue; + dfs(next.e); + + } + // 현재 사람의 바로 옆 사람이 원수라면 + else { + // 옆사람과 옆옆사람이 원수일 때, 현재 사람과 같은 팀을 할 수 있음 + for(Node nnext: adj[next.e]) { + if(check[nnext.e] || nnext.isFriend) continue; + dfs(nnext.e); + } + } + } + } + + static void initInput() throws Exception { + BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + StringTokenizer st; + + int n = Integer.parseInt(br.readLine()); + check = new boolean[n + 1]; + adj = new ArrayList[n + 1]; + + for(int i = 0; i < adj.length; i++) adj[i] = new ArrayList(); + + int m = Integer.parseInt(br.readLine()); + + for(int i = 0; i < m; i++) { + st = new StringTokenizer(br.readLine()); + + boolean isFriend = st.nextToken().charAt(0) == 'F'; + + int p = Integer.parseInt(st.nextToken()); + int q = Integer.parseInt(st.nextToken()); + + adj[p].add(new Node(q, isFriend)); + adj[q].add(new Node(p, isFriend)); + } + } +} \ No newline at end of file diff --git "a/BOJ/1000-5000\353\262\210/DH_2258.java" "b/BOJ/1000-5000\353\262\210/DH_2258.java" index c94c5b8a..26c4b978 100644 --- "a/BOJ/1000-5000\353\262\210/DH_2258.java" +++ "b/BOJ/1000-5000\353\262\210/DH_2258.java" @@ -6,66 +6,61 @@ */ public class DH_2258 { - + static class Node implements Comparable { int w, c; - + public Node(int w, int c) { this.w = w; this.c = c; } - public Node(int w, int c, int sum) { - this.w = w; - this.c = c; - } - @Override public int compareTo(Node o) { - if (this.c != o.c) - return Integer.compare(this.c, o.c); // 가격 오름차순 + if(this.c != o.c) return Integer.compare(this.c, o.c); // 가격 오름차순 return Integer.compare(o.w, this.w); // 무게 내림차순 } } - - static final int INF = Integer.MAX_VALUE; - + static final Long INF = Long.MAX_VALUE; + public static void main(String[] args) throws Exception { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(br.readLine()); PriorityQueue pq = new PriorityQueue(); - + int N = Integer.parseInt(st.nextToken()); // 덩어리의 개수 long M = Integer.parseInt(st.nextToken()); // 필요한 고기의 양 - - for (int r = 0; r < N; r++) { + + for(int r = 0; r < N; r++) { st = new StringTokenizer(br.readLine()); int a = Integer.parseInt(st.nextToken()); int b = Integer.parseInt(st.nextToken()); - + pq.add(new Node(a, b)); } - - int result = INF; + + long result = INF; long totalSum = 0; - int totalCost = 0, same = 0, markCost = -1; - - while (!pq.isEmpty()) { + long totalCost = 0; + int same = 0, markCost = -1; + + while(!pq.isEmpty()) { Node current = pq.poll(); - - if (markCost != current.c) { + + if(markCost != current.c) { markCost = current.c; same = 0; } else same += current.c; totalSum += current.w; totalCost = current.c; - if (totalSum >= M) + if(totalSum >= M) { result = Math.min(result, totalCost + same); + } } - - System.out.println(result == INF ? -1 : result); + + System.out.println(result == INF ? -1: result); } } diff --git "a/BOJ/1000-5000\353\262\210/DH_3109.java" "b/BOJ/1000-5000\353\262\210/DH_3109.java" new file mode 100644 index 00000000..38fa0145 --- /dev/null +++ "b/BOJ/1000-5000\353\262\210/DH_3109.java" @@ -0,0 +1,71 @@ +import java.io.*; +import java.util.*; + +/* + * 빵집 + */ + +public class DH_3109 { + static int[] dr = {-1, 0, 1}, dc = {1, 1, 1}; + static int R, C, cnt; + static char[][] map; + static boolean flag; + + public static void main(String[] args) throws Exception { + initInput(); + solution(); + + System.out.println(cnt); + } + + static void solution() { + for(int r = 0; r < R; r++) { + flag = false; + dfs(r, 0); // (r, 0)에서 dfs 시작 + } + } + + static void dfs(int r, int c) { + if(c == C - 1) { + cnt += 1; + flag = true; + return; + } + + for(int d = 0; d < 3; d++) { + int nr = r + dr[d]; + int nc = c + dc[d]; + + if(!check(nr, nc) || map[nr][nc] == 'x' || flag) continue; + map[nr][nc] = 'x'; + dfs(nr, nc); + } + } + + static boolean check(int r, int c) { + return r >= 0 && r < R && c >= 0 && c < C; + } + + static void initInput() throws Exception { + BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + StringTokenizer st = new StringTokenizer(br.readLine()); + + R= Integer.parseInt(st.nextToken()); + C = Integer.parseInt(st.nextToken()); + + map = new char[R][C]; + + for(int r = 0; r < R; r++) { + String str = br.readLine(); + map[r] = str.toCharArray(); + } + } + + static void printMap(char[][] map) { + for(int r = 0; r < map.length; r++) { + System.out.println(Arrays.toString(map[r])); + } + + System.out.println(); + } +} diff --git "a/BOJ/20001-25000\353\262\210/DH_20061.java" "b/BOJ/20001-25000\353\262\210/DH_20061.java" new file mode 100644 index 00000000..4a88e97b --- /dev/null +++ "b/BOJ/20001-25000\353\262\210/DH_20061.java" @@ -0,0 +1,227 @@ +import java.io.*; +import java.util.*; + +/* + * 모노미노도미노 2 + * 오답이었던 이유 + * 1. 연한 곳 블럭 내리고 안 없앰 + * 2. static과 local과 Arrays.copy... + * - checkColorBoardRow 부분에서 처음엔 마지막에 map = tmp로 했었음 + * * 근데 값이 안변함 + * * 원인: 전역변수를 직접적으로 바꾸어 주지 않고, 전역변수의 메서드 로컬 변수로 전달했기 때문 + * 메서드 로컬 변수는 메서드 내부에서만 존재하고 함수가 끝나면 사라지는 존재임! + * - tmp[r] = Arrays.copyOf(tmp[r], COLUMN)으로 해결 + */ + +public class DH_20061 { + + static final int ROW = 6, COLUMN = 4; + + static class Point { + int r, c; + public Point (int r, int c) { + this.r = r; + this.c = c; + } + + public void rotate() { + int tmp = r; + this.r = c; + this.c = COLUMN - 1 - tmp; + } + } + static int score; + static boolean[][] green, blue; + + public static void main(String[] args) throws Exception { + + green = new boolean[ROW][COLUMN]; // 초록색 보드 + blue = new boolean[ROW][COLUMN]; // 파란색 보드 + + BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + StringTokenizer st; + + int N = Integer.parseInt(br.readLine()); + + for(int tc = 0; tc < N; tc++) { + + st = new StringTokenizer(br.readLine()); + + int t = Integer.parseInt(st.nextToken()); + int r = Integer.parseInt(st.nextToken()); + int c = Integer.parseInt(st.nextToken()); + + // 빨간색 보드에 (r, c)를 놓았을 때, + // t와 보드의 색을 고려하여 추가되는 보드의 좌표가 달라져야 함 + ArrayList greenPoints = new ArrayList<>(); + ArrayList bluePoints = new ArrayList<>(); + + + Point greenPoint = new Point(0, c); + Point bluePoint = new Point(r, c); + + bluePoint.rotate(); + bluePoint.r = 0; + + greenPoints.add(greenPoint); + bluePoints.add(bluePoint); + + // t가 2일 때 + // 초록색 보드에는 1 × 2 크기의 블럭 + // 파란색 보드에는 2 x 1 크기의 블럭 + if(t == 2) { + greenPoints.add(new Point(0, c + 1)); + bluePoints.add(new Point(bluePoint.r + 1, bluePoint.c)); + } + + // t가 3일 때 + // 초록색 보드에는 2 × 1 크기의 블럭 + // 파란색 보드에는 1 x 2 크기의 블럭 + if(t == 3) { + greenPoints.add(new Point(greenPoint.r + 1, greenPoint.c)); + bluePoints.add(new Point(0, bluePoint.c - 1)); + } + + putBlock(green, greenPoints); // 빨간색 보드에 있는 블럭을 초록색 보드에 옮겨주기 + checkColorBoardRow(green); // 초록색 보드의 행을 보면서 꽉 찬 행이 있는지 확인 + checkBeforeSecondRow(green); + + putBlock(blue, bluePoints); + checkColorBoardRow(blue); + checkBeforeSecondRow(blue); + } + + StringBuilder sb = new StringBuilder(); + sb.append(score).append("\n").append(countBlockCnt()); + System.out.println(sb); + } + + // 보드에서 블럭들의 개수 세기 + static int countBlockCnt() { + int count = 0; + + for(int r = 0; r < ROW; r++) { + for(int c = 0; c < COLUMN; c++) { + if(blue[r][c]) count += 1; + if(green[r][c]) count += 1; + } + } + + return count; + } + + // 빨간색 보드에 있는 블럭 (초록/파란)색 보드에 넣기 + static void putBlock(boolean[][] map, ArrayList points) { + + int startRow = 0; + + // 행의 기준을 0부터 시작하면서 블럭을 어디에서 시작 행을 어디서부터 할 수 있는지 확인하기 + L: for(int r = 0; r < ROW; r++) { + + // 블럭에 속하는 모든 좌표들이 들어갈 수 있어야 됨 + for(Point p: points) { + int currentR = r + p.r; + if(currentR >= ROW || map[currentR][p.c]) break L; + } + startRow = r; + } + + // 보드에 블럭들 넣어주기 + for(Point p: points) map[(startRow + p.r)][p.c] = true; + } + + // 꽉 찬 행을 찾고 블럭들을 없애줌 + static void checkColorBoardRow(boolean[][] map) { + // 타일이 꽉 찬 행과 열의 idx를 저장하는 set + Set set = new HashSet(); + + // 행이 모두 꽉 차있다면 해당 행을 set에 저장 + checkIsFillFullRow(set, map); + + // 점수는 set의 size + score += set.size(); + + // set에 있는 행들을 비우기 + if(!set.isEmpty()) removeBlocks(set, map); + } + + // 0~2행에 블럭이 있는지 확인하고, 하단에 있는 블럭 없애주기 + static void checkBeforeSecondRow(boolean[][] map) { + int checkRowNumber = -1; + + L: for(int r = 0; r < 2; r++) { + + for(int c = 0; c < COLUMN; c++) { + if(map[r][c]) { + checkRowNumber = r; + break L; + } + } + } + + if(checkRowNumber == -1) return; + + // checkRowNumber가 0이면 아래에서 두 칸 없애야 됨 + // checkRownumber가 1이면 아래에서 한 칸 없애야 됨 + int diff = checkRowNumber == 0 ? 2: 1; + + for(int r = ROW - 1; r >= 0; r--) { + + Arrays.fill(map[r], false); + for(int c = 0; c < COLUMN; c++) { + if(r - diff >= 0) map[r][c] = map[r - diff][c]; + else map[r][c] = false; + } + } + } + + // 꽉찬 행의 블럭들 없애기 + static void removeBlocks(Set set, boolean[][] map) { + + for(int idx: set) { + for(int c = 0; c < COLUMN; c++) { + map[idx][c] = false; + } + } + + boolean[][] tmp = new boolean[ROW][COLUMN]; + + // 없어진 곳 기준 위에 내리기 + int currentIdx = ROW - 1; + + for(int r = ROW - 1; r >= 0; r--) { + + boolean isEmpty = true; + for(int c = 0; c < COLUMN; c++) { + if(map[r][c]) { + isEmpty = false; + break; + } + } + + if(isEmpty) continue; + + tmp[currentIdx] = Arrays.copyOf(map[r], map[r].length); + currentIdx -= 1; + } + + for(int r = 0; r < ROW; r++) map[r] = Arrays.copyOf(tmp[r], COLUMN); + } + + // 행이 보드로 꽉 찼는지 확인 + static void checkIsFillFullRow(Set set, boolean[][] map) { + for(int r = 0; r < ROW; r++) { + boolean isFillFull = true; + + for(int c = 0; c < COLUMN; c++) { + if(!map[r][c]) { + isFillFull = false; + break; + } + } + + if(!isFillFull) continue; + set.add(r); + } + } +} \ No newline at end of file diff --git a/Programmers/Level2/DH_12905.java b/Programmers/Level2/DH_12905.java new file mode 100644 index 00000000..eb956385 --- /dev/null +++ b/Programmers/Level2/DH_12905.java @@ -0,0 +1,25 @@ +/* +가장 큰 정사각형 + */ + +public class DH_12905 { + public int solution(int [][]board) { + int[][] dp = new int[board.length][board[0].length]; + + int answer = 0; + + for(int r = 0; r < board.length; r++) { + for(int c = 0; c < board[0].length; c++) { + if(board[r][c] == 0) continue; + if(r == 0 || c == 0) dp[r][c] = 1; + else { + dp[r][c] = Math.min(dp[r - 1][c - 1], Math.min(dp[r][c - 1], dp[r - 1][c])) + 1; + } + + answer = Math.max(answer, dp[r][c]); + } + } + + return answer * answer; + } +} \ No newline at end of file diff --git a/Programmers/Level2/DH_258711.java b/Programmers/Level2/DH_258711.java new file mode 100644 index 00000000..5858ca23 --- /dev/null +++ b/Programmers/Level2/DH_258711.java @@ -0,0 +1,50 @@ +import java.util.*; + +/* + * 도넛과 막대 그래프 + */ + +class DH_258711 { + static HashMap hashMap = new HashMap<>(); + + static int[] solution(int[][] edges) { + + int[] answer = new int[4]; + for(int[] edge: edges) { + + int a = edge[0]; // [0]: 나가는거 + int b = edge[1]; // [1]: 들어오는거 + + hashMap.put(a, hashMap.getOrDefault(a, new int[2])); + hashMap.put(b, hashMap.getOrDefault(b, new int[2])); + + hashMap.get(a)[0] += 1; + hashMap.get(b)[1] += 1; + } + + for(int node: hashMap.keySet()) { + int[] count = hashMap.get(node); + + // 나가는 간선: 2개 이상, 들어오는 간선: 0개 -> 생성된 노드 + if(count[0] >= 2 && count[1] == 0) answer[0] = node; + + // 나가는 간선: 0개, 들어오는 간산: 0개 이상 -> 직선 그래프 + else if(count[0] == 0 && count[1] > 0) answer[2] += 1; + + // 나가는 간선: 2개 이상, 들어오는 간선: 2개 이상 -> 8자 그래프 + else if(count[0] >= 2 && count[1] >= 2) answer[3] += 1; + } + + // 생성된 노드에서 나가는 간선의 개수: 총 그래프의 개수 + answer[1] = hashMap.get(answer[0])[0] - (answer[2] + answer[3]); + return answer; + } + + public static void main(String[] args) { +// int[][] edges = {{2, 3}, {4, 3}, {1, 1}, {2, 1}}; + int[][] edges = {{4, 10}, {1, 12}, {8, 3}, {12, 7}, {4, 2}, {7, 11}, {4, 8}, {9, 6}, + {10, 11}, {6, 10}, {3, 5}, {11, 1}, {5, 3}, {11, 9}, {3, 8}}; + + System.out.println(Arrays.toString(solution(edges))); + } +} diff --git a/Programmers/Level2/DH_86052.java b/Programmers/Level2/DH_86052.java new file mode 100644 index 00000000..32ded162 --- /dev/null +++ b/Programmers/Level2/DH_86052.java @@ -0,0 +1,108 @@ +import java.util.*; + +/* + * 빛의 경로 사이클 + */ + +public class DH_86052 { + static class Node { + // Node가 [r][c] 지점일 때, [r][c]에서 dir 방향으로 갈 때, 현재 거리 + // 변수명은 dir이지만, 방향이 아닌 거리를 저장 + int[] dir; + + public Node(int[] dir) { + this.dir = dir; + } + } + + static int[] dr = {-1, 0, 1, 0}, dc = {0, 1, 0, -1}; // 상, 우, 하, 좌 + + static int[] solution(String[] grid) { + + int row = grid.length, column = grid[0].length(); + + ArrayList answerList = new ArrayList<>(); + + // 빛의 경로들 저장 + Node[][] nodeMap = initNodeMap(row, column); + + // 모든 격자 확인 + for(int r = 0; r < row; r++) { + for(int c = 0; c < column; c++) { + + // 한 격자에 대해 상, 우, 하, 좌 모두 확인 + for(int d = 0; d < 4; d++) { + + // 사이클이 발생하는지 확인 (사이클 발생 → 0 보다 큰 숫자 반환) + int cycleLength = getCycleLength(grid, nodeMap, r, c, d); + if(cycleLength == 0) continue; + answerList.add(cycleLength); + } + } + } + + Collections.sort(answerList); + int[] answer = new int[answerList.size()]; + for(int i = 0; i < answerList.size(); i++) answer[i] = answerList.get(i); + + return answer; + } + + // 사이클이 발생하는지 확인하는 함수 + static int getCycleLength(String[] grid, Node[][] nodeMap, int sr, int sc, int sd) { + + char startCh = grid[sr].charAt(sc); + if(startCh == 'L') sd = (sd + 4 - 1) % 4; + if(startCh == 'R') sd = (sd + 4 + 1) % 4; + + // 초기 시작 좌표와 방향 저장 + int initR = sr, initC = sc, initD = sd; + + int dis = 0; + int r = grid.length, c = grid[0].length(); + + while(true) { + // dis가 0이 아니면서 현재 시작 좌표와 방향이 초기 좌표와 방향과 같다면 사이클이 발생한 것 + if(dis != 0 && sr == initR && sc == initC && sd == initD) return dis; + if(nodeMap[sr][sc].dir[sd] != 0) break; // 만약에 dir[sd] != 0이라면 이미 사이클이 발생하는지 확인한 경로 + + // 현재 좌표에서 가야되는 방향을 거리로 채워넣기 + nodeMap[sr][sc].dir[sd] = ++ dis; + + // 다음 좌표 구하기 + int nr = (sr + r + dr[sd]) % r; + int nc = (sc + c + dc[sd]) % c; + int nd = sd; + + // 다음 좌표에서의 방향 구하기 + if(grid[nr].charAt(nc) == 'L') nd = (nd + 4 - 1) % 4; + if(grid[nr].charAt(nc) == 'R') nd = (nd + 4 + 1) % 4; + + // 현재 좌표 업데이트 + sr = nr; + sc = nc; + sd = nd; + } + + return 0; + } + + static Node[][] initNodeMap(int row, int column) { + Node[][] nodeMap = new Node[row][column]; + + for(int r = 0; r < row; r++) { + for(int c = 0; c < column; c++) { + int[] dir = new int[4]; + + nodeMap[r][c] = new Node(dir); + } + } + + return nodeMap; + } + + public static void main(String[] args) { + String[] grid = {"SL", "LR"}; + System.out.println(Arrays.toString(solution(grid))); + } +} diff --git "a/SQL/17\354\243\274\354\260\250/DH_Odd and Even.sql" "b/SQL/17\354\243\274\354\260\250/DH_Odd and Even.sql" new file mode 100644 index 00000000..e7e0ac7d --- /dev/null +++ "b/SQL/17\354\243\274\354\260\250/DH_Odd and Even.sql" @@ -0,0 +1,7 @@ +SELECT + transaction_date + , SUM(CASE WHEN MOD(amount, 2) = 0 THEN 0 ELSE amount END) AS odd_sum + , SUM(CASE WHEN MOD(amount, 2) = 1 THEN 0 ELSE amount END) as even_sum +FROM TRANSACTIONS +GROUP BY transaction_date +ORDER BY transaction_date ASC \ No newline at end of file diff --git "a/SQL/17\354\243\274\354\260\250/DH_Restaurant Growth.sql" "b/SQL/17\354\243\274\354\260\250/DH_Restaurant Growth.sql" new file mode 100644 index 00000000..59d452ef --- /dev/null +++ "b/SQL/17\354\243\274\354\260\250/DH_Restaurant Growth.sql" @@ -0,0 +1,15 @@ +# AMOUNT OVER SUM TABLE +WITH AOST AS ( + SELECT + visited_on, + SUM(amount) OVER(ORDER BY visited_on RANGE BETWEEN INTERVAL 6 DAY PRECEDING AND CURRENT ROW) `amount`, + MIN(visited_on) OVER() min_date + FROM CUSTOMER +) + +SELECT + DISTINCT(visited_on) + , amount + , round(amount / 7, 2) `average_amount` +FROM AOST +WHERE min_date + 6 <= visited_on \ No newline at end of file