C# 코딩테스트 강좌, 최소 공배수 구하기

이번 강좌에서는 코딩 테스트에서 자주 출제되는 “최소 공배수(Lowest Common Multiple, LCM)” 문제를 해결하는 방법에 대해 알아보겠습니다. 최소 공배수는 두 개 이상의 수들에서 공통적으로 나누어 떨어지는 가장 작은 양의 정수를 의미합니다. 이 개념은 수학적으로 중요한 성질을 가지며, 알고리즘적 문제 해결에서도 자주 사용됩니다.

문제 설명

주어진 두 양의 정수 A와 B에 대해, A와 B의 최소 공배수를 구하는 프로그램을 작성하시오.

예제:
A = 12, B = 15
출력: 60 (12와 15의 최소 공배수)

문제 해결 과정

문제를 해결하기 위해서는 최소 공배수를 구하는 방법을 이해해야 합니다. 일반적으로 최소 공배수는 최대 공약수(Greatest Common Divisor, GCD)를 이용하여 구할 수 있습니다. 두 수 A와 B의 최소 공배수는 다음과 같이 표현됩니다:

LCM(A, B) = (A * B) / GCD(A, B)

이를 통해 최소 공배수를 구하기 위해서는 두 수의 곱을 최대 공약수로 나누어 주면 됩니다. 이제 C#으로 이 알고리즘을 구현해 보겠습니다.

최대 공약수 구하기

최대 공약수는 유클리드 호제법을 사용하여 쉽게 구할 수 있습니다. 유클리드 호제법의 기본 원리는 다음과 같습니다:

GCD(A, B) = GCD(B, A % B) (B가 0이 될 때까지 반복)

이제 이를 C#으로 구현해 보겠습니다.

C# 코드 구현


using System;

class Program
{
    // 최대 공약수를 구하는 메서드
    static int GCD(int a, int b)
    {
        while (b != 0)
        {
            int temp = b;
            b = a % b;
            a = temp;
        }
        return a;
    }

    // 최소 공배수를 구하는 메서드
    static int LCM(int a, int b)
    {
        return (a * b) / GCD(a, b);
    }

    static void Main(string[] args)
    {
        Console.Write("첫 번째 정수를 입력하세요: ");
        int a = int.Parse(Console.ReadLine());
        
        Console.Write("두 번째 정수를 입력하세요: ");
        int b = int.Parse(Console.ReadLine());

        Console.WriteLine($"최소 공배수는: {LCM(a, b)}입니다.");
    }
}
    

위 코드는 사용자가 입력한 두 정수의 최소 공배수를 계산하여 출력합니다. GCD 메서드는 최대 공약수를 계산하고, LCM 메서드는 최소 공배수를 계산하는 역할을 수행합니다.

코드 설명

1. 최대 공약수 메서드

GCD(int a, int b) 메서드는 두 정수 a와 b를 인자로 받아 최대 공약수를 반환합니다. while 루프를 이용해 b가 0이 아닐 때까지 반복하며, a와 b의 값을 업데이트합니다. 이를 통해 유클리드 호제법을 구현하였습니다.

2. 최소 공배수 메서드

LCM(int a, int b) 메서드는 최소 공배수를 구하기 위해 두 수의 곱을 최대 공약수로 나누고 결과를 반환합니다. 이 과정에서 정수 오버플로우를 방지하기 위해 순서를 잘 고려해야 합니다.

3. Main 메서드

Main 메서드에서는 사용자로부터 두 개의 정수를 입력받고, 이를 이용하여 LCM 메서드를 통해 결과를 출력합니다. Console.ReadLine()을 통해 입력값을 받고, int.Parse()로 정수형으로 변환합니다.

테스트와 예외 처리

이번 강좌에서 구현한 최소 공배수 프로그램은 간단하지만, 몇 가지 예외 상황을 고려해야 할 필요가 있습니다. 예를 들어 사용자가 0이나 음의 정수를 입력하는 경우, 이러한 입력을 처리할 수 있는 방법을 고려해야 합니다. 이를 위해 다음과 같은 예외 처리를 추가할 수 있습니다:


static void Main(string[] args)
{
    try
    {
        Console.Write("첫 번째 정수를 입력하세요: ");
        int a = int.Parse(Console.ReadLine());
        if (a <= 0) throw new ArgumentException("양의 정수를 입력해야 합니다.");

        Console.Write("두 번째 정수를 입력하세요: ");
        int b = int.Parse(Console.ReadLine());
        if (b <= 0) throw new ArgumentException("양의 정수를 입력해야 합니다.");

        Console.WriteLine($"최소 공배수는: {LCM(a, b)}입니다.");
    }
    catch (FormatException)
    {
        Console.WriteLine("잘못된 입력입니다. 정수를 입력해 주세요.");
    }
    catch (ArgumentException ex)
    {
        Console.WriteLine(ex.Message);
    }
    catch (Exception ex)
    {
        Console.WriteLine("알 수 없는 오류가 발생했습니다: " + ex.Message);
    }
}
    

위의 코드에서 try-catch 블록을 사용하여 다양한 예외를 처리하고 있습니다. 사용자가 유효하지 않은 값을 입력했을 경우, 적절한 오류 메시지를 출력하여 프로그램이 비정상 종료되는 것을 방지할 수 있습니다.

효율성 및 최적화

이번 문제 해결 과정에서 사용된 유클리드 호제법은 최대 공약수를 매우 효율적으로 계산할 수 있도록 설계되어 있습니다. 이러한 알고리즘은 O(log(min(A, B))) 시간 복잡도를 갖기 때문에, 매우 큰 수의 최소 공배수를 구할 때에도 효율적으로 작동합니다. 이 점에서, 알고리즘의 성능은 매우 중요한 요소입니다.

마무리

이번 강좌에서는 C#을 사용하여 최소 공배수를 구하는 알고리즘을 구현해 보았습니다. 각 메서드의 기능을 이해하고, 예외 처리와 효율성에 대한 내용을 함께 다루어 보았습니다. 최소 공배수는 다양한 문제에서 응용되므로, 이 알고리즘을 잘 숙지해 두는 것이 중요합니다. 앞으로도 다양한 알고리즘 문제를 풀어보며 실력을 쌓아가시길 바랍니다!

여기까지 읽어주셔서 감사합니다. 다음 강좌에서는 다른 알고리즘 문제 해결 방법에 대해 알아보도록 하겠습니다.

C# 코딩테스트 강좌, 신기한 소수 찾기

현대의 소프트웨어 개발 환경에서는 코딩 테스트가 중요한 요소로 자리매김하고 있습니다.
기업들은 지원자의 알고리즘적 사고와 문제 해결 능력을 평가하기 위해 다양한 문제를 제시합니다.
이번 블로그에서는 신기한 소수 찾기라는 주제로 코딩 테스트 문제를 함께 풀어보도록 하겠습니다.

문제 설명

주어진 정수 N 이하의 모든 소수를 찾아서 출력하는 프로그램을 작성하시오.
단, 소수는 1과 자기 자신 외에는 나누어 떨어지지 않는 자연수이며,
2 이상인 자연수 중에서 1과 자신만을 약수로 가지는 수를 뜻합니다.

입력

첫 번째 줄에 정수 N이 입력된다. (2 <= N <= 1000000)

출력

N 이하의 모든 소수를 한 줄에 하나씩 출력한다.

문제 접근 방법

소수를 찾는 문제에서 가장 일반적인 방법은 에라토스테네스의 체를 사용하는 것입니다.
이 알고리즘은 효율적이며 N의 크기가 큰 경우에도 사용할 수 있습니다.
에라토스테네스의 체를 사용하면 다음과 같은 순서로 소수를 찾을 수 있습니다.

  1. 2부터 N까지의 모든 수를 나열합니다.
  2. 2부터 시작하여 해당 수의 배수를 모두 제거합니다.
  3. 다음으로 남아 있는 수 가운데 가장 작은 수를 선택하고,
    동일한 방식으로 해당 수의 배수를 제거합니다.
  4. 이 과정을 N의 제곱근보다 작은 수들에 대해 반복합니다.
  5. 남아 있는 수들은 모두 소수입니다.

C# 코드 구현

다음은 위의 알고리즘을 C#으로 구현한 코드입니다:

        
        using System;
        using System.Collections.Generic;

        class Program {
            static void Main(string[] args) {
                int N = int.Parse(Console.ReadLine());
                bool[] isPrime = new bool[N + 1];
                
                for (int i = 2; i <= N; i++) {
                    isPrime[i] = true; // 모든 수를 소수로 초기화
                }

                for (int i = 2; i * i <= N; i++) {
                    if (isPrime[i]) { // i가 소수인 경우
                        for (int j = i * i; j <= N; j += i) {
                            isPrime[j] = false; // i의 배수를 소수가 아님으로 설정
                        }
                    }
                }

                for (int i = 2; i <= N; i++) {
                    if (isPrime[i]) {
                        Console.WriteLine(i); // 소수 출력
                    }
                }
            }
        }
        
    

코드 설명

위 코드는 C#을 사용하여 에라토스테네스의 체 알고리즘을 구현한 것입니다.
각 줄을 자세히 살펴보며 설명하겠습니다.

  • using System;: C#의 시스템 네임스페이스를 사용하기 위해 추가합니다.
  • using System.Collections.Generic;: 리스트와 같은 컬렉션을 사용하기 위해 필요합니다.
  • int N = int.Parse(Console.ReadLine());: 사용자로부터 입력을 받아 N에 저장합니다.
  • bool[] isPrime = new bool[N + 1];: 0부터 N까지의 각 숫자가 소수인지 여부를 저장하기 위해 배열을 생성합니다.
  • for (int i = 2; i <= N; i++) { isPrime[i] = true; }: 모든 수를 소수로 초기화합니다.
  • for (int i = 2; i * i <= N; i++) { … }: N의 제곱근까지 반복하면서 소수를 찾습니다.
  • if (isPrime[i]) { … }: i가 소수라면, 그 배수를 모두 소수가 아님으로 설정합니다.
  • for (int i = 2; i <= N; i++) { if (isPrime[i]) { Console.WriteLine(i); }}: 최종적으로 남아 있는 소수를 출력합니다.

효율성

에라토스테네스의 체 알고리즘은 O(N log log N)의 시간 복잡도를 가지며,
공간 복잡도는 O(N)입니다. 따라서 N이 1,000,000과 같은 큰 수일지라도
충분히 빠르게 소수를 찾을 수 있습니다.

결론

이번 포스팅에서는 C#을 이용한 신기한 소수 찾기 문제를 해결하기 위해
에라토스테네스의 체 알고리즘을 사용하여 소수를 찾는 방법에 대해 알아보았습니다.
알고리즘 문제 해결 능력은 코딩 테스트 뿐만 아니라 실제 개발에서도 매우 중요하므로,
지속적인 학습과 연습을 통해 능력을 강화해 나가시기 바랍니다.
다음 포스팅에서는 보다 다양한 문제를 통해 알고리즘적 사고를 확장해보도록 하겠습니다.

C# 코딩테스트 강좌, 선택 정렬

안녕하세요! 오늘은 C#을 활용한 코딩테스트 강좌를 진행하겠습니다. 이번 주제는 알고리즘의 기초 중 하나인 선택 정렬입니다. 선택 정렬은 간단하면서도 직관적으로 이해할 수 있는 정렬 알고리즘입니다. 이 강좌에서는 선택 정렬의 개념, 알고리즘의 작동 방식, 구현 방법, 그리고 실제 문제를 예시로 들어 선택 정렬을 어떻게 활용할 수 있는지 설명하겠습니다.

1. 선택 정렬이란?

선택 정렬은 주어진 리스트에서 가장 작은(혹은 가장 큰) 값을 찾아서 해당 값을 리스트의 첫 번째 위치와 교환하는 방식으로 정렬을 수행합니다. 다음으로 남은 리스트에서 다시 가장 작은 값을 찾아서 그 값을 두 번째 위치와 교환합니다. 이러한 과정을 반복하여 모든 요소가 정렬될 때까지 계속하는 것이 선택 정렬의 원리입니다.

2. 알고리즘의 작동 방식

선택 정렬의 동작 방식을 단계별로 살펴보겠습니다. 주어진 리스트가 [64, 25, 12, 22, 11]이라고 가정해 보겠습니다.

  • 1단계: 전체 리스트에서 가장 작은 값을 찾습니다. 11이 가장 작으므로, 11과 64를 교환합니다. (현재 리스트: [11, 25, 12, 22, 64])
  • 2단계: 남은 리스트에서 가장 작은 값을 찾습니다. 12가 가장 작으므로, 12와 25를 교환합니다. (현재 리스트: [11, 12, 25, 22, 64])
  • 3단계: 남은 리스트에서 22가 가장 작으니, 22와 25를 교환합니다. (현재 리스트: [11, 12, 22, 25, 64])
  • 4단계: 마지막으로 25와 25를 교환합니다. (현재 리스트: [11, 12, 22, 25, 64])

이러한 방식으로 리스트가 정렬됩니다. 정렬 과정은 최악의 경우 및 평균적으로 O(n^2)의 시간 복잡도를 가집니다.

3. C#으로 선택 정렬 구현하기

다음으로 C#에서 선택 정렬을 구현해 보겠습니다. 아래 코드는 선택 정렬 알고리즘을 사용하여 배열을 정렬하는 C# 프로그램입니다.


using System;

class SelectionSort
{
    static void Main(string[] args)
    {
        int[] array = { 64, 25, 12, 22, 11 };
        
        Console.WriteLine("정렬 전 배열:");
        PrintArray(array);
        
        SelectionSort(array);
        
        Console.WriteLine("정렬 후 배열:");
        PrintArray(array);
    }
    
    static void SelectionSort(int[] arr)
    {
        int n = arr.Length;
        
        for (int i = 0; i < n - 1; i++)
        {
            int minIndex = i;
            
            for (int j = i + 1; j < n; j++)
            {
                if (arr[j] < arr[minIndex])
                {
                    minIndex = j;
                }
            }
            
            // Swap 최소값을 현재 위치의 값과 교환
            if (minIndex != i)
            {
                int temp = arr[i];
                arr[i] = arr[minIndex];
                arr[minIndex] = temp;
            }
        }
    }
    
    static void PrintArray(int[] arr)
    {
        foreach (int num in arr)
        {
            Console.Write(num + " ");
        }
        Console.WriteLine();
    }
}

4. 코드 설명

코드에 대해 간단히 설명하겠습니다. SelectionSort 클래스 안에 Main 메서드가 있습니다. 이 메서드는 프로그램의 시작점으로, 미리 정의된 배열을 선언하고 정렬 전 후의 배열을 출력합니다.

SelectionSort 메서드는 선택 정렬 알고리즘의 핵심 로직을 포함하고 있습니다. 이 메서드는 주어진 배열을 순회하며 각 위치에서 최소값의 인덱스를 찾아내고, 그 값을 현재 위치의 값과 교환합니다. PrintArray 메서드는 배열의 모든 요소를 출력하는 기능을 수행합니다.

5. 선택 정렬의 장점과 단점

장점

  • 구현이 간단하고 직관적입니다.
  • 메모리 사용이 적습니다. 추가 메모리를 거의 쓰지 않기 때문에, O(1)의 공간 복잡도를 가집니다.

단점

  • 시간 복잡도가 높아(최악의 경우 O(n^2)), 대량의 데이터에는 적합하지 않습니다.
  • 정렬이 안정적이지 않습니다. 중복된 값이 있을 경우 상대적인 순서가 보장되지 않습니다.

6. 활용 가능한 문제 예제

코딩 테스트에서 선택 정렬을 활용할 수 있는 상황을 예시로 들어보겠습니다. 예를 들어, 주어진 학생들의 성적을 오름차순으로 정렬한 후, 성적에 따라 학점을 부여하는 프로그램을 구현할 수 있습니다. 문제는 다음과 같습니다:

문제: 학생들의 성적을 담고 있는 배열이 주어질 때, 선택 정렬 알고리즘을 사용하여 성적을 오름차순으로 정렬하시오.

입력

10, 3, 76, 34, 2, 45, 65, 23, 90

출력

2, 3, 10, 23, 34, 45, 65, 76, 90

위 문제를 선택 정렬을 통해 해결할 수 있으며, 코드 구현은 이전의 선택 정렬 코드를 응용하면 됩니다.

7. 결론

이번 강좌를 통해 선택 정렬에 대해 알아보았습니다. 선택 정렬은 간단하지만 알기 쉬운 정렬 알고리즘으로, 기본적인 알고리즘의 작동 원리를 이해하는 데 큰 도움이 됩니다. 또한 C#을 활용하여 직접 구현해 보면서 알고리즘의 동작 과정을 체험할 수 있었습니다. 정치적 알고리즘 문제에서 선택 정렬을 어떻게 활용할 수 있는지에 대해 알아보았고, 여러분도 다양한 문제에 적용해 보시기 바랍니다!

다음 강좌에서는 다른 정렬 알고리즘인 삽입 정렬에 대해 다루도록 하겠습니다. 감사합니다!

C# 코딩테스트 강좌, 외판원의 순회 경로 짜기

코딩테스트에서 자주 출제되는 문제 중 하나가 바로 ‘외판원의 순회 문제’입니다. 이 문제는 주어진 여러 도시들 사이를 여행하며 돌아오는 경로를 최소 비용으로 찾는 문제입니다. 이 문제는 NP-완전 문제에 속하여, 최적해를 찾는 것이 매우 어렵습니다. 따라서, 다양한 탐색 알고리즘을 통해 근사적인 해를 찾거나, 동적 프로그래밍(DP)을 이용하여 최적해를 찾는 방식이 일반적입니다.

문제 정의

n개의 도시가 있으며, 각 도시는 서로 다른 다른 도시와 연결되어 있다고 가정합니다. 각 도시 간의 이동 비용이 주어질 때, 모든 도시를 한 번씩 방문하고 출발 도시로 되돌아오는 최소 비용의 순회를 출력하시오.

입력

  • 첫 번째 줄에는 도시의 수 n (1 ≤ n ≤ 10)이 주어진다.
  • 다음 n개의 줄에는 n x n 크기의 인접 행렬이 주어진다. 각 행렬의 원소는 두 도시 간의 이동 비용을 나타낸다. 이동 비용이 없는 경우에는 0이 주어진다.

출력

모든 도시를 한 번씩 방문하고 다시 출발지로 돌아오는 최소 비용을 출력한다.

예제

        입력:
        4
        0 10 15 20
        10 0 35 25
        15 35 0 30
        20 25 30 0

        출력:
        80
    

문제 해결 과정

1. 문제 분석

문헌에 따르면 이 문제는 NP-완전 문제로 알려져 있어, 모든 가능한 경로를 시도하는 완전 탐색 방식으로 접근할 수 있습니다. 그러나 도시의 수가 10개 이하일 때는 이러한 방식이 실효성이 있다는 것을 보여줄 수 있습니다. 각 도시를 한 번씩 방문하는 경우의 수는 (n-1)! 이기 때문에, n이 10일 경우 9! = 362880 이라는 충분히 계산 가능한 범위입니다.

2. 알고리즘 선택

여기서는 백트래킹 기법을 통해 모든 경로를 탐색하여 최소 비용을 계산하는 알고리즘을 선택하겠습니다. 이 알고리즘은 현재 도시를 기준으로 가능한 경로를 재귀적으로 탐색하며, 더 이상 진행할 수 없는 경우에는 이전 단계로 돌아가서 다른 경로를 시도합니다. 이를 통해 모든 경우의 수를 고려하여 최소 비용을 찾을 수 있습니다.

3. C# 코드 구현

        
        using System;

        class Program
        {
            static int n; // 도시의 수
            static int[,] cost; // 이동 비용 행렬
            static bool[] visited; // 방문 도시 체크
            static int minCost = int.MaxValue; // 최소 비용

            static void Main(string[] args)
            {
                n = int.Parse(Console.ReadLine());
                cost = new int[n, n];
                visited = new bool[n];

                for (int i = 0; i < n; i++)
                {
                    var line = Console.ReadLine().Split();
                    for (int j = 0; j < n; j++)
                    {
                        cost[i, j] = int.Parse(line[j]);
                    }
                }

                visited[0] = true; // 시작 도시 방문 표시
                FindPath(0, 0, 1); // 현재 도시(0), 현재 비용(0), 방문 도시 수(1)
                Console.WriteLine(minCost);
            }

            static void FindPath(int currentCity, int currentCost, int count)
            {
                if (count == n && cost[currentCity, 0] != 0) // 모든 도시를 방문했다면
                {
                    minCost = Math.Min(minCost, currentCost + cost[currentCity, 0]);
                    return;
                }

                for (int nextCity = 0; nextCity < n; nextCity++)
                {
                    if (!visited[nextCity] && cost[currentCity, nextCity] != 0)
                    {
                        visited[nextCity] = true;
                        FindPath(nextCity, currentCost + cost[currentCity, nextCity], count + 1);
                        visited[nextCity] = false; // 백트래킹
                    }
                }
            }
        }
        
        

4. 코드 설명

위의 코드는 도시 수를 입력받아 주어진 인접 행렬을 생성합니다. 그런 다음, FindPath 함수를 사용하여 모든 경로를 탐색합니다. 이 함수의 주요 매개변수는 다음과 같습니다:

  • currentCity: 현재 방문 중인 도시
  • currentCost: 지금까지의 이동 비용
  • count: 현재까지 방문한 도시 수

기본적으로 시작 도시는 방문 표시가 되어 있으며, 모든 도시를 방문하게 되면 처음 도시로의 경비를 계산하고 최소 비용과 비교합니다. 만약, 더 줄일 수 있다면 minCost를 갱신합니다.

5. 시간 복잡도

이 문제의 시간 복잡도는 O(n!)입니다. 모든 도시를 방문하는 조합을 탐색하므로 도시 수가 증가할수록 계산량이 기하급수적으로 증가하게 됩니다.

결론

이번 강좌를 통해 외판원의 순회의 최소 비용을 찾는 문제를 C#로 해결하는 방법을 다루었습니다. 해당 문제는 기본적인 백트래킹 알고리즘을 통해 해결할 수 있으며, 더 좋은 효율성을 위해 다양한 최적화 기법과 동적 프로그래밍을 활용할 수도 있습니다. 향후에는 이러한 기법들에 대해서도 다루어보도록 하겠습니다.

C# 코딩테스트 강좌, 케빈 베이컨의 6단계 법칙

이번 글에서는 매우 흥미로운 개념인 “케빈 베이컨의 6단계 법칙”에 대해 알아보겠습니다. 이 법칙은 모든 사람이 6단계 이내에 케빈 베이컨과 연결될 수 있다는 이론입니다. 영화 산업에서 자주 인용되며, 사회적 네트워킹 이론에서도 중요한 역할을 합니다. 우리는 이 개념을 바탕으로 알고리즘 문제를 풀어보겠습니다.

문제 설명

다음과 같은 조건의 알고리즘 문제를 다룹니다:

문제 제목: 케빈 베이컨의 친구 찾기

문제 설명: N명의 배우가 있고, 각 배우는 다른 배우와 친구일 수 있습니다. 주어진 N명의 배우와 그들의 친구 관계가 있을 때, 각 배우와 케빈 베이컨 간의 관계의 최소 단계(최소 친구의 수)가 몇 단계인지 계산하는 문제입니다. 이러한 관계는 비행기로 비유할 수 있으며, 관계의 간선은 서로가 친구임을 의미합니다.

한 배우 A와 다른 배우 B의 친구 관계가 주어진다면, 두 배우는 1단계 관계에 있습니다. A와 B의 친구 C가 있다면, A와 C는 2단계 관계에 있습니다. 이와 같이 진행하여, 모든 배우들과 케빈 베이컨 간의 최소 친구 관계를 계산해야 합니다.

입력 형식

  • 첫 번째 줄에 자연수 N (1 ≤ N ≤ 100)과 M (0 ≤ M ≤ 10,000)이 주어집니다.
  • 두 번째 줄 부터 M줄에 걸쳐서 두 배우의 친구 관계가 주어집니다. 예를 들어 “1 2″는 1번 배우와 2번 배우가 서로 친구임을 의미합니다.

출력 형식

각 배우에 대해 케빈 베이컨과의 최소 관계의 단계를 출력합니다. 만약 케빈 베이컨과 관계가 없다면 -1을 출력해야 합니다.

입력 예시

5 4
1 2
1 3
2 4
3 5

출력 예시

2
3
3

문제 풀이 접근 방식

이 문제를 해결하기 위해서는 그래프 탐색 알고리즘을 사용할 수 있습니다. 친구 관계를 그래프로 구성하고, 각 배우에서 케빈 베이컨까지의 최단 경로를 찾는 방식입니다. 이를 위해 다음과 같은 단계를 따릅니다:

  1. 그래프 구성: 주어진 친구 관계를 인접 리스트 방식으로 그래프를 구성합니다.
  2. BFS (너비 우선 탐색): 모든 배우에 대해 BFS를 수행하여 케빈 베이컨까지의 최단 경로를 찾습니다.
  3. 출력: 각 배우와 케빈 베이컨의 최소 관계 단계를 계산하여 출력합니다.

코드 구현

이제 위의 접근 방식을 C#으로 구현해보겠습니다.


using System;
using System.Collections.Generic;

class Program
{
    static void Main(string[] args)
    {
        int N, M;
        string[] firstLine = Console.ReadLine().Split();
        N = int.Parse(firstLine[0]);
        M = int.Parse(firstLine[1]);

        List[] graph = new List[N + 1];
        for (int i = 1; i <= N; i++)
        {
            graph[i] = new List();
        }

        for (int i = 0; i < M; i++)
        {
            string[] edge = Console.ReadLine().Split();
            int u = int.Parse(edge[0]);
            int v = int.Parse(edge[1]);
            graph[u].Add(v);
            graph[v].Add(u); // 친구 관계는 양방향입니다.
        }

        int[] distances = new int[N + 1];

        for (int i = 1; i <= N; i++)
        {
            BFS(graph, distances, i);
        }

        for (int i = 1; i < distances.Length; i++)
        {
            Console.WriteLine(distances[i] == 0 ? -1 : distances[i]);
        }
    }

    static void BFS(List[] graph, int[] distances, int start)
    {
        Queue queue = new Queue();
        bool[] visited = new bool[graph.Length];
        int[] localDistances = new int[graph.Length];
        
        queue.Enqueue(start);
        visited[start] = true;

        while (queue.Count > 0)
        {
            int node = queue.Dequeue();

            foreach (var neighbor in graph[node])
            {
                if (!visited[neighbor])
                {
                    visited[neighbor] = true;
                    queue.Enqueue(neighbor);
                    localDistances[neighbor] = localDistances[node] + 1;
                }
            }
        }

        for (int j = 1; j < distances.Length; j++)
        {
            if (distances[j] == 0 && localDistances[j] > 0)
            {
                distances[j] = localDistances[j];
            }
        }
    }
}

해설

이 코드에서는 먼저 배우의 수와 친구 관계의 수를 입력받고, 친구 관계를 기반으로 그래프를 구성합니다. 이후 각 배우에 대해 BFS를 수행하여 케빈 베이컨까지의 거리를 계산합니다. BFS는 큐를 활용하여 현재 노드와 연결된 모든 노드를 탐색하고, 최단 거리 계산에 매우 적합한 알고리즘입니다.

각 배우 별로 BFS 결과를 통해 최소 친구 관계 단계를 출력합니다. 만약 케빈 베이컨과 연결되지 않았다면, -1을 출력하도록 설정했습니다.

최적화 및 추가 사항

정확한 결과를 얻기 위해 몇 가지 최적화를 고려할 수 있습니다:

  • 친구 관계가 없는 경우를 고려하여 초기 거리 배열을 설정할 때, 모든 요소를 -1로 초기화할 수 있습니다.
  • BFS를 통해 탐색할 때, 중복 노드를 제거하여 메모리를 절약할 수 있습니다.

결론

이번 강좌에서는 케빈 베이컨의 6단계 법칙을 기반으로 알고리즘 문제를 풀어보았습니다. 그래프 탐색 알고리즘의 중요성과 BFS의 활용을 통해 여러 문제를 해결할 수 있는 능력을 키우시길 바랍니다. 문제를 풀면서 직면한 어려움을 해결하고, 다양한 해법을 시도해보는 것이 알고리즘 실력을 향상시키는 데 큰 도움이 됩니다.

앞으로도 다양한 알고리즘 문제를 다루며, 이론과 실전 코딩이 결합된 교육 콘텐츠를 제공할 예정입니다. 많은 관심과 응원 부탁드립니다.

© 2023 알고리즘 강좌. 모든 권리 보유.