스위프트 코딩테스트 강좌, 거짓말쟁이가 되긴 싫어

효과적인 알고리즘 문제풀이를 위해 다양한 문제를 함께 풀어보는 강좌입니다. 오늘 우리가 다룰 문제는 ‘거짓말쟁이가 되긴 싫어’라는 주제를 기반으로 하고 있습니다. 이 문제를 통해 통계적 사고와 조건문, 리스트 처리 기술을 익히게 될 것입니다.

문제 설명

최근에 한 참가자가 날라리로 선발된 결혼식에 참석하게 되었습니다. 그런데 그 결혼식에는 그가 원치 않는 친구가 100명이나 초대되어 있었습니다. 이들은 결혼식에서 자신의 친구가 아닌 타인을 거짓말로 소개할 계획을 세우고 있습니다.

각 친구들은 특정 인원에 대해 ‘나는 A와 B를 알고 있다’ 라고 주장할 수 있습니다. 여러분의 임무는 모든 거짓말을 확인하고서 두 친구들이 같은 사람을 알고 있는지 판별하는 것입니다.

주어진 입력은 친구의 수, 각 친구의 거짓말 정보가 포함됩니다. 여러분은 입력된 정보를 바탕으로 과연 어떤 친구가 거짓말을 하는지를 판단해야 합니다.

입력 예시

                5
                1 2
                2 3
                3 4
                4 5
                1 5
            

첫 줄에는 친구의 수 N이 주어지고, 이후 N줄에는 각각의 친구가 알고 있는 친구의 번호가 주어집니다.

출력 예시

                Yes
            

두 친구가 서로를 알고 있을 경우 ‘Yes’, 그렇지 않을 경우는 ‘No’를 출력합니다.

문제 접근법

이 문제를 해결하기 위해서는 그래프 탐색 알고리즘을 이용할 수 있습니다. 각각의 친구들을 정점으로 하고, 그들 사이의 관계를 간선으로 표현하여 그래프를 구성합니다. DFS나 BFS와 같은 탐색 방식을 사용하여 두 친구가 서로를 알고 있는지를 확인할 수 있습니다.

기본적인 접근 방법은 친구 관계를 리스트에 저장하고, 주어진 두 친구에 대해 그래프 탐색을 실시하는 것입니다.

코드 구현

아래는 스위프트로 구현한 코드입니다.

                
                import Foundation

                func canKnowEachOther(N: Int, friendships: [(Int, Int)], friendA: Int, friendB: Int) -> String {
                    // 그래프 초기화
                    var graph = Array(repeating: [Int](), count: N + 1)

                    // 친구 관계 저장
                    for (a, b) in friendships {
                        graph[a].append(b)
                        graph[b].append(a)
                    }

                    // BFS 초기화
                    var queue = [friendA]
                    var visited = Array(repeating: false, count: N + 1)
                    visited[friendA] = true

                    while !queue.isEmpty {
                        let current = queue.removeFirst()

                        // 친구 B를 발견했는가?
                        if current == friendB {
                            return "Yes"
                        }

                        for neighbor in graph[current] {
                            if !visited[neighbor] {
                                visited[neighbor] = true
                                queue.append(neighbor)
                            }
                        }
                    }

                    return "No"
                }

                // 입력 예시
                let N = 5
                let friendships = [(1, 2), (2, 3), (3, 4), (4, 5), (1, 5)]
                let result = canKnowEachOther(N: N, friendships: friendships, friendA: 1, friendB: 5)
                print(result) // "Yes"
                
            

코드 설명

위의 코드는 다음과 같은 방식으로 동작합니다:

  • 그래프 초기화: 입력 받은 친구 관계를 바탕으로 인접 리스트 형태로 그래프를 초기화합니다.
  • BFS 탐색: 주어진 친구 A에서 시작하여 BFS를 실행하면서 친구 B에 도착했는지를 확인합니다. 이미 방문한 친구는 다시 방문하지 않도록 관리합니다.
  • 결과 반환: 친구 B를 발견하면 “Yes”를 반환하고, 모든 탐색을 마친 후에도 발견하지 못했을 경우 “No”를 반환합니다.

추가적 고려사항

이 문제의 해결 방법은 기본적인 DFS/BFS 탐색이기 때문에 굉장히 직관적입니다. 하지만 문제의 범위가 증가하게 되면 더 효율적인 방법을 모색해야 할 수도 있습니다. 예를 들어, 친구 수가 많아질 경우 DFS 대신 Union-Find 알고리즘을 적용하는 것이 성능상 유리할 수 있습니다.

만약 더 복잡한 관계나 무작위적 구성의 데이터가 주어진다면 이를 해결하기 위해 다양한 기법(예: Dynamic Programming 옵션 등)을 활용할 수 있습니다. 알고리즘 설계 시 최악의 경우 시간 복잡도와 공간 복잡도를 고려하여 선택하는 것이 매우 중요합니다.

이 글은 스위프트 코딩테스트에 관한 여러 문제 풀이를 위한 강좌의 일환입니다. 문제 이해와 해결 방법을 통해 여러분의 문제 해결 능력을 키우길 바랍니다.