Programmers. 순위

문제 https://school.programmers.co.kr/learn/courses/30/lessons/49191 풀이 처음에 문제를 막 읽었을 때는 조금 어려워 보이지만, 문장을 살짝 다르게 해석해보자. ‘정확하게 순위를 매길 수 있는 선수의 수’를 알아야 하는데 정확하게 순위를 매긴다는 것은 어떨 때 성립할까? 특정 선수 A가 존재할 때, A와 서로 승패를 알 수 없는 선수 B가 존재하면 정확하게 순위를 매길 수 없는 것이다. 반대로 A가 다른 모든 선수들과 확실하게 승패의 결과를 알 수 있다면, 정확하게 순위를 매길 수 있다. 문제에서는 경기 결과를 제공해주므로, 선수들의 실력을 간접적으로 알 수 있다. 실력을 수치화 해서 관리할 수 있으면 좋지만, 그럴게 할 수 없는 조건이고 그럴 필요도 없다. 단순하게 선수들간의 ‘승’, ‘패’ 결과를 그래프로 관리해주면 된다. 승리 그래프와 패배 그래프를 따로 만들어서, 경기 결과를 그래프로 표현하고, 각 선수마다 이 선수가 승리할 선수, 패배할 선수의 수를 세어주면 된다. 특정 선수가 다른 모든 선수들과 확실하게 승패의 결과를 알 수 있다는 것은, 결국 승리할 선수와 패배할 선수의 합이 현재 선수를 제외한 나머지 선수의 수와 같은 것이기 때문이다. ...

August 5, 2025

BOJ 7490. 0 만들기

문제 https://www.acmicpc.net/problem/7490 풀이 DFS 문제이다. 3가지 연산자 (" ", "+", "-")를 배치하는 모든 경우의 수를 수식으로 만든 후 계산하면 된다. 코드 import Foundation func calcuate() { var rawExpression = "" for idx in 0..<n - 1 { rawExpression += String(seq[idx]) rawExpression += cal[idx] } rawExpression += String(seq[n - 1]) let expression = rawExpression.replacingOccurrences(of: " ", with: "") var numbers = [Int]() var operators = [Character]() var numBuffer = "" for element in expression { if element.isNumber { numBuffer.append(element) } else { numbers.append(Int(numBuffer)!) operators.append(element) numBuffer = "" } } if let lastNumber = Int(numBuffer) { numbers.append(lastNumber) } var result = numbers[0] for idx in 0..<operators.count { if operators[idx] == "-" { result -= numbers[idx + 1] } else { result += numbers[idx + 1] } } if result == 0 { print(rawExpression) } } func dfs() { if cal.count == n - 1 { calcuate() return } for op in [" ", "+", "-"] { cal.append(op) dfs() cal.removeLast() } } let t = Int(readLine()!)! var n = Int() var seq = [Int]() var cal = [String]() for _ in 0..<t { n = Int(readLine()!)! seq = Array(1...n) cal = [] dfs() print() }

June 10, 2024

BOJ 2668. 숫자고르기

문제 https://www.acmicpc.net/problem/2668 풀이 문제를 간단하게 표현하면 그래프 내의 사이클을 모두 찾은 다음에, 사이클에 포함되는 노드을 모두 출력하면 된다. 사이클을 찾으려면 그래프내의 모든 노드에서 dfs를 쓰면 되는데 다음과 같은 케이스들로 나눌 수 있겠다. 1. 사이클에 도달하긴 하나 시작 노드는 사이클에 포함되지 않는 케이스 주어진 예제에서 2번, 4번, 6번, 7번 노드가 해당한다. 탐색을 시작한 노드에서 사이클에 도달하긴 하나, 시작한 노드는 사이클에 포함되지 않는다. 최적화를 위해 이러한 케이스에도 사이클만 따로 분리해 중복되는 연산을 줄일 수 있겠지만, 이 문제의 n이 큰 수가 아니므로, 그냥 아무런 행동도 하지 않는다. ...

June 4, 2024

BOJ 12100. 2048(Easy)

문제 https://www.acmicpc.net/problem/12100 풀이 최대 20 * 20 크기의 보드에서 2048 게임을 하는 것이다. 최대 5번의 이동만 한다고 문제에 주어져 있으므로, 모든 경우를 탐색하여 문제를 풀 수 있다. 이 문제에서 주의해야할 점은 다음과 같다. 이동하는 방향에서 가까운 숫자부터 이동해야한다. 한 번의 이동동안 이미 합쳐진 숫자는 다시 합쳐지지 않는다. 이 두가지 조건만 잘 생각하면서 작성하면 된다. 코드 import Foundation func dfs(_ size: Int) { if size == 5 { for row in 0..<n { for column in 0..<n { answer = max(answer, graph[row][column]) } } return } for i in 0..<4 { let currentGraph = graph shift(i) dfs(size + 1) graph = currentGraph } } func shift(_ order: Int) { var isMerged = [[Bool]](repeating: [Bool](repeating: false, count: n), count: n) if order == 0 { for row in 0..<n { for column in 0..<n { if graph[row][column] != 0 { var newRow = row while newRow > 0 { if graph[newRow - 1][column] == 0 { let temp = graph[newRow][column] graph[newRow][column] = graph[newRow - 1][column] graph[newRow - 1][column] = temp newRow -= 1 } else if graph[newRow][column] == graph[newRow - 1][column] { if isMerged[newRow - 1][column] { break } let temp = graph[newRow][column] graph[newRow][column] = graph[newRow - 1][column] graph[newRow - 1][column] = temp * 2 graph[newRow][column] = 0 isMerged[newRow - 1][column] = true break } else { break } } } } } } if order == 1 { for column in 0..<n { for row in (0..<n).reversed() { if graph[row][column] != 0 { var newRow = row while newRow < n - 1 { if graph[newRow + 1][column] == 0 { let temp = graph[newRow][column] graph[newRow][column] = graph[newRow + 1][column] graph[newRow + 1][column] = temp newRow += 1 } else if graph[newRow][column] == graph[newRow + 1][column] { if isMerged[newRow + 1][column] { break } let temp = graph[newRow][column] graph[newRow][column] = graph[newRow + 1][column] graph[newRow + 1][column] = temp * 2 graph[newRow][column] = 0 isMerged[newRow + 1][column] = true break } else { break } } } } } } if order == 2 { for row in 0..<n { for column in 0..<n { if graph[row][column] != 0 { var newColumn = column while newColumn > 0 { if graph[row][newColumn - 1] == 0 { let temp = graph[row][newColumn] graph[row][newColumn] = graph[row][newColumn - 1] graph[row][newColumn - 1] = temp newColumn -= 1 } else if graph[row][newColumn] == graph[row][newColumn - 1] { if isMerged[row][newColumn - 1] { break } let temp = graph[row][newColumn] graph[row][newColumn] = graph[row][newColumn - 1] graph[row][newColumn - 1] = temp * 2 graph[row][newColumn] = 0 isMerged[row][newColumn - 1] = true break } else { break } } } } } } if order == 3 { for row in 0..<n { for column in (0..<n).reversed() { if graph[row][column] != 0 { var newColumn = column while newColumn < n - 1 { if graph[row][newColumn + 1] == 0 { let temp = graph[row][newColumn] graph[row][newColumn] = graph[row][newColumn + 1] graph[row][newColumn + 1] = temp newColumn += 1 } else if graph[row][newColumn] == graph[row][newColumn + 1] { if isMerged[row][newColumn + 1] { break } let temp = graph[row][newColumn] graph[row][newColumn] = graph[row][newColumn + 1] graph[row][newColumn + 1] = temp * 2 graph[row][newColumn] = 0 isMerged[row][newColumn + 1] = true break } else { break } } } } } } } var n = Int(readLine()!)! var graph = [[Int]]() for _ in 0..<n { graph.append(readLine()!.split(separator: " ").map { Int(String($0))! }) } var answer = 0 dfs(0) print(answer)

April 14, 2024

BOJ 14502. 연구소

문제 https://www.acmicpc.net/problem/14502 풀이 dfs와 bfs가 합쳐진 문제이다. 벽을 꼭 3개를 세워야 하므로 dfs를 이용하여 벽을 세울 위치를 전체 탐색할 수 있다. 연구소의 크기가 최대 8 * 8 이므로 전체 탐색하는데 큰 문제가 발생하지 않는다. 벽을 세웠으면 bfs를 이용하여 바이러스가 퍼졌을 때의 연구소의 모습을 그린다. 이 때 바이러스가 지나간 자리는 2로 마킹되고, 벽은 바이러스가 지나가지 못하므로 isVisited와 같은 배열이 없어도 이미 지나간 곳임을 알 수 있다. 알고리즘을 순서대로 나타내면 다음과 같다. ...

July 5, 2023

BOJ 1260. dfs와 bfs

문제 https://www.acmicpc.net/problem/1260 풀이 심플하다. 입력값으로 그래프가 주어지고, DFS와 BFS를 이용해 탐색한 결과를 각각 출력하면 된다. 코드 from collections import deque def dfs(v, dfsArray): isVisitedDFS[v] = True dfsArray.append(v) for i in range(len(graph[v])): if graph[v][i] != 0 and isVisitedDFS[i] == False: dfs(i, dfsArray) def bfs(v, bfsArray): QueueBFS = deque() isVisitedBFS[v] = True QueueBFS.append(v) while len(QueueBFS) != 0: node = QueueBFS.popleft() bfsArray.append(node) for i in range(len(graph[node])): if graph[node][i] != 0 and not isVisitedBFS[i] QueueBFS.append(i) isVisitedBFS[i] = True n, m, v = map(int, input().split()) graph = [[0] * (n + 1) for i in range(n + 1)] isVisitedDFS = [False for i in range(n + 1)] isVisitedBFS = [False for i in range(n + 1)] dfsArray = [] bfsArray = [] for i in range(m): a, b = map(int, input().split()) graph[a][b] = graph[b][a] = 1 dfs(v, dfsArray) bfs(v, bfsArray) for node in dfsArray: print(node, end=" ") print() for node in bfsArray: print(node, end=" ") print()

November 6, 2022

BOJ 10451. 순열 사이클

문제 https://www.acmicpc.net/problem/10451 풀이 순열이 각각의 (1부터 시작하는)인덱스와 매칭되어있는 그래프를 만들면 쉽게 해결된다. (친절하게 문제에 그림도 있다.) 순열과 인덱스는 내부 원소들이 순서를 제외하고 같으므로 무조건 내부에 사이클을 형성하게 된다. 따라서 문제에서 주어진 그대로 우리는 서로 가르키는 방향을 재귀로 따라가고, 이미 방문한 숫자가 나온다면 재귀를 종료시키기를 반복해서 생기는 사이클의 총 개수를 카운트 하기만 하면 된다. 코드 def dfs(v, start): isVisited[v] = True if not isVisited[permutation[v - 1]]: dfs(permutation[v - 1], start) n = [] per = [] t = int(input()) for _ in range(t): n_temp = int(input()) per_temp = list(map(int, input().split())) n.append(n_temp) per.append(per_temp) for case in range(t): count = 0 isVisited = [False] * (n[case] + 1) permutation = per[case] for i in range(1, n[case] + 1): if not isVisited[i]: dfs(i, i) count += 1 print(count) 굳이 재귀를 쓰지 않더라도 반복문만으로도 깔끔한 코드가 나올것 같다.

November 6, 2022