C# 코딩테스트 강좌, 구간 곱 구하기

문제 설명

주어진 정수 배열 nums와 쿼리 배열 queries가 있습니다. 각 쿼리는 두 정수 (l, r)로 이루어져 있으며, 이는 nums[l] * nums[l + 1] * ... * nums[r]의 값을 구하라는 요청입니다. 단, nums 배열의 크기는 최대 10^5, queries의 길이는 최대 10^4입니다. 이때, 곱셈의 결과가 매우 커질 수 있으므로, 결과는 10^9 + 7로 나눈 나머지를 출력해야 합니다.

입력 형식

첫 번째 줄에 배열의 크기 n과 쿼리의 수 q가 주어집니다. 두 번째 줄에 n개의 정수로 이루어진 배열 nums가 주어지고, q개의 줄에 걸쳐 각 쿼리 lr가 주어집니다.

출력 형식

각 쿼리에 대해 계산한 결과를 한 줄에 하나씩 출력합니다.

예시

입력
5 3
2 3 4 5 6
0 2
1 3
2 4
출력
24
60
120

문제 풀이

이 문제를 해결하기 위해서는 구간 곱을 빠르게 계산할 수 있는 방법이 필요합니다. 단순히 각 쿼리에 대해 구간을 순회하면서 곱을 계산하면 시간 복잡도 O(q * n)에 이르게 되어, 최악의 경우 10^9의 연산을 수행할 수 있습니다. 이는 실용적이지 않기 때문에, Prefix Product를 사용하여 시간 복잡도를 줄이는 전략을 사용합니다.

Prefix Product 방법

우선, nums 배열의 원소들에 대한 누적 곱을 저장하여 쿼리의 결과를 빠르게 계산할 수 있도록 합니다.

C#
int mod = 1000000007;
int[] prefixProduct = new int[n + 1];
prefixProduct[0] = 1;

for (int i = 1; i <= n; i++) {
    prefixProduct[i] = (int)((1L * prefixProduct[i - 1] * nums[i - 1]) % mod);
}

여기서 prefixProduct[i]nums[0] * nums[1] * ... * nums[i - 1]의 값을 저장합니다. 이 구조를 통해 우리는 구간 곱을 쉽고 빠르게 계산할 수 있습니다.

구간 곱 계산하기

이제 각 쿼리 (l, r)에 대해, 구간 곱 nums[l] * nums[l + 1] * ... * nums[r]는 다음과 같이 구할 수 있습니다:

C#
int result = (int)((1L * prefixProduct[r + 1] * modInverse(prefixProduct[l]) % mod) % mod);

여기서 modInverse 함수는 모듈로 연산에 대한 역원을 구하는 함수입니다. 역원은 다음과 같이 구현할 수 있습니다:

C#
int modInverse(int a) {
    return power(a, mod - 2);
}

int power(int x, int y) {
    int res = 1;
    while (y > 0) {
        if ((y & 1) == 1) {
            res = (int)((1L * res * x) % mod);
        }
        y >>= 1;
        x = (int)((1L * x * x) % mod);
    }
    return res;
}

최종 코드

위의 설명을 토대로 전체 코드를 작성하면 다음과 같습니다:

C#
using System;

class Program {
    static int mod = 1000000007;

    static void Main() {
        string[] firstLine = Console.ReadLine().Split();
        int n = int.Parse(firstLine[0]);
        int q = int.Parse(firstLine[1]);
        int[] nums = Array.ConvertAll(Console.ReadLine().Split(), int.Parse);
        int[] prefixProduct = new int[n + 1];
        prefixProduct[0] = 1;

        for (int i = 1; i <= n; i++) {
            prefixProduct[i] = (int)((1L * prefixProduct[i - 1] * nums[i - 1]) % mod);
        }

        for (int i = 0; i < q; i++) {
            string[] query = Console.ReadLine().Split();
            int l = int.Parse(query[0]);
            int r = int.Parse(query[1]);
            int result = (int)((1L * prefixProduct[r + 1] * modInverse(prefixProduct[l]) % mod) % mod);
            Console.WriteLine(result);
        }
    }

    static int modInverse(int a) {
        return power(a, mod - 2);
    }

    static int power(int x, int y) {
        int res = 1;
        while (y > 0) {
            if ((y & 1) == 1) {
                res = (int)((1L * res * x) % mod);
            }
            y >>= 1;
            x = (int)((1L * x * x) % mod);
        }
        return res;
    }
}

결론

이번 강좌에서는 배열의 구간 곱을 효과적으로 계산하기 위해 Prefix Product 방법과 모듈로 연산의 역원의 개념을 활용하는 방법을 학습했습니다. 이 방법을 응용하면 더욱 복잡한 쿼리 처리에도 유용하게 활용할 수 있을 것입니다. C# 언어의 특징을 살려 효율적인 코드를 작성하고, 알고리즘 문제 해결 능력을 한층 더 향상시킬 수 있습니다.

추가적으로, 이 문제에서 사용한 Prefix Product 기법은 다양한 형태의 쿼리 문제에서 유용하게 적용될 수 있으므로, 다양한 문제에 적용해보는 것도 좋습니다. 감사합니다!

C# 코딩테스트 강좌, 계단 수 구하기

1. 문제 설명

계단 수는 특정 조건에 맞는 수를 세는 문제입니다.
주어진 수 N이 있을 때, N 자리의 계단 수를 구하는 문제를 다루겠습니다.
계단 수란 각 자리의 수가 그 다음 자리 수보다 1만큼 크거나 작아야 하는 수입니다. 예를 들어, 1234, 3210은 계단 수입니다.
그러나 1123, 2222는 계단 수가 아닙니다.
이 문제를 통해 동적 프로그래밍의 기본 아이디어와 구현 방법을 이해할 수 있습니다.

2. 입력 & 출력 형식

입력

N (1 ≤ N ≤ 100), 주어진 자연수인 N은 계단 수의 자리 수를 나타냅니다.

출력

N자리 계단 수의 개수를 1,000,000,000으로 나눈 나머지를 출력합니다.

3. 문제 접근 방법

계단 수를 세기 위해서는 동적 프로그래밍(Dynamic Programming) 방식을 선택해야 합니다.
문제를 풀기 위해 다음과 같은 방법으로 접근할 수 있습니다.
N자리 계단 수를 구하기 위해, (N-1)자리 계단 수를 이용하여 값을 계산합니다.
다음과 같은 규칙을 찾아낼 수 있습니다:

  • 각 자리 수가 0이면, 다음 자리 수는 1만 올 수 있습니다.
  • 각 자리 수가 9이면, 다음 자리 수는 8만 올 수 있습니다.
  • 각 자리 수가 1~8인 경우, 다음 자리 수는 그보다 1 작거나 큰 두 가지 선택이 가능합니다.

이를 바탕으로 DP 테이블을 구성하고, 각 자리수에 따른 계단 수를 기록해 나가면서
최종적으로 N자리 계단 수를 구할 수 있습니다.
DP 배열을 초기화하고, 점차적으로 채워나가는 방식으로 접근합니다.

4. C# 코드 구현

이제 본격적으로 C#으로 계단 수를 구하는 코드를 구현해 보겠습니다.
아래는 문제 해결을 위한 C# 코드입니다.


using System;

class Program
{
    static void Main()
    {
        int N = int.Parse(Console.ReadLine());
        long[,] dp = new long[N + 1, 10];

        // 1자리 계단 수 초기화 (1~9)
        for (int i = 1; i <= 9; i++)
        {
            dp[1, i] = 1;
        }

        // DP를 활용하여 N자리 계단수 구하기
        for (int i = 2; i <= N; i++)
        {
            for (int j = 0; j <= 9; j++)
            {
                if (j == 0)
                {
                    dp[i, j] = dp[i - 1, j + 1] % 1000000000; // 0 -> 1
                }
                else if (j == 9)
                {
                    dp[i, j] = dp[i - 1, j - 1] % 1000000000; // 9 -> 8
                }
                else
                {
                    dp[i, j] = (dp[i - 1, j - 1] + dp[i - 1, j + 1]) % 1000000000; // j-1, j+1
                }
            }
        }

        // N자리 계단수의 총합 계산
        long result = 0;
        for (int j = 0; j <= 9; j++)
        {
            result = (result + dp[N, j]) % 1000000000;
        }

        // 결과 출력
        Console.WriteLine(result);
    }
}
            

5. 코드 설명

위의 코드를 단계별로 설명하겠습니다.
1. 우선, 사용자의 입력으로부터 N을 읽어옵니다.
2. 2차원 배열 dp를 생성하여 dp[i, j]는 i자리의 계단 수 중 j로 끝나는 수의 개수를 저장합니다.
3. 1자리 수는 0~9 중에서 1~9만 사용 가능하므로 이를 초기화합니다.
4. 이후, 2자리부터 N자리까지 각 자리수를 계산합니다.
5. 각 자리수의 계산은 위에서 설명한 규칙에 따라 이루어집니다.
6. 마지막으로 N자리의 계단수를 모두 합산하여 결과를 출력합니다.

6. 복잡도 분석

이 알고리즘의 시간 복잡도는 O(N)입니다.
N이 100일 때, 2중 루프를 통해서 각 자리수에 대한 가능성을 확인하므로
O(N) * O(10) = O(N)에 해당합니다.
공간 복잡도는 O(N * 10)이며, 이는 메모리 사용량이 비교적 적다는 것을 의미합니다.

7. 예제

입력 예시


3
            

출력 예시


32
            

위의 예제에서 3자리 계단 수는 32개가 존재합니다.
이를 통해 문제를 이해할 수 있습니다.

8. 결론

이 강좌에서는 계단 수를 구하는 문제를 통해 동적 프로그래밍의 기초적인
개념을 익혔습니다.
계단 수 문제는 알고리즘 스킬을 향상시키는 데 도움이 되는 좋은 연습 문제가 될 수 있습니다.
다양한 문제를 풀어보면서 더 많은 경험을 쌓길 바랍니다.
앞으로도 알고리즘 문제 풀이에 도전하세요!

C# 코딩테스트 강좌, 이분 그래프 판별하기

1. 서론

그래프 이론은 컴퓨터 과학과 알고리즘의 중요한 분야로, 다양한 실제 문제를 해결하는 데 활용됩니다.
이 글에서는 ‘이분 그래프’의 개념과 이를 판별하는 알고리즘 문제를 소개하고, C#으로 이를 해결하는 방법을
자세히 설명하겠습니다. 이분 그래프란 그래프의 정점을 두 개의 집합으로 나눈 후, 같은 집합의 정점끼리는
연결되지 않도록 만들어진 그래프를 말합니다. 이러한 그래프는 여러 가지 응용 분야에서 중요한 역할을 합니다.
예를 들어, 두 종류의 객체 간의 연결 관계나 이분 매칭 문제 등에서 자주 사용됩니다.

2. 문제 설명

이 문제에서는 그래프가 주어졌을 때, 이분 그래프인지 아닌지를 판별하는 알고리즘을 구현해야 합니다.
예를 들어, 그래프의 정점 수 V와 간선 수 E가 주어지고, V개의 정점과
E개의 간선이 이어져 있습니다. 주어진 그래프가 이분 그래프일 경우에는 “YES”를 출력하고, 그렇지 않을 경우에는
“NO”를 출력해야 합니다.

입력 형식

        첫 번째 줄에는 정점의 수 V와 간선의 수 E가 주어진다.
        다음 E개의 줄에는 간선의 양 끝 점을 나타내는 두 정수가 주어진다.
    

출력 형식

        주어진 그래프가 이분 그래프일 경우 "YES", 그렇지 않을 경우 "NO"를 출력한다.
    

3. 알고리즘 접근 방식

이 문제를 해결하기 위해, 우리가 사용할 알고리즘은 BFS (너비 우선 탐색) 또는 DFS (깊이 우선 탐색)입니다.
이분 그래프 판별을 위해 각 정점을 두 개의 색으로 칠하는 방법을 사용할 것입니다.
즉, 하나의 집합은 색상 1로 표시하고 다른 집합은 색상 2로 표시합니다. 만약 인접한 두 정점이 동일한 색상으로
칠해진다면 이분 그래프가 아니라는 것을 의미합니다.

알고리즘 단계

  1. 그래프를 인접 리스트 형식으로 나타내기 위해 데이터 구조를 생성합니다.
  2. BFS 또는 DFS를 사용하여 정점을 방문하며, 정점의 색상을 결정합니다.
  3. 인접한 정점이 동일한 색상인지 체크하여 이분 그래프 여부를 판단합니다.
  4. 모든 정점을 방문하고 나서 최종 결과를 출력합니다.

4. C# 코드 구현

이제 앞서 설명한 알고리즘을 바탕으로 C#으로 코드를 구현하겠습니다.
아래는 이분 그래프 판별을 위한 C# 코드입니다.

using System;
using System.Collections.Generic;

class Program
{
    static List[] graph;
    static int[] color;

    static void Main(string[] args)
    {
        string[] input = Console.ReadLine().Split();
        int V = int.Parse(input[0]);
        int E = int.Parse(input[1]);

        graph = new List[V + 1];
        for (int i = 0; i <= V; i++)
            graph[i] = new List();

        for (int i = 0; i < E; i++)
        {
            input = Console.ReadLine().Split();
            int u = int.Parse(input[0]);
            int v = int.Parse(input[1]);
            graph[u].Add(v);
            graph[v].Add(u);
        }

        color = new int[V + 1];

        bool isBipartite = true;
        for (int i = 1; i <= V; i++)
        {
            if (color[i] == 0)
                isBipartite &= BFS(i);
        }

        Console.WriteLine(isBipartite ? "YES" : "NO");
    }

    static bool BFS(int start)
    {
        Queue queue = new Queue();
        queue.Enqueue(start);
        color[start] = 1;  // 최초 정점 색칠

        while (queue.Count > 0)
        {
            int node = queue.Dequeue();
            foreach (int neighbor in graph[node])
            {
                if (color[neighbor] == 0)  // 아직 색칠 안 된 경우
                {
                    color[neighbor] = 3 - color[node];  // 현재 정점과 다른 색
                    queue.Enqueue(neighbor);
                }
                else if (color[neighbor] == color[node])  // 인접한 두 정점 색이 같으면
                {
                    return false;
                }
            }
        }
        return true;
    }
}
    

5. 코드 설명

위 C# 코드에서 사용된 주요 구성 요소와 로직을 설명하겠습니다.

자료구조

List[] graph: 그래프를 인접 리스트로 표현하기 위해 사용됩니다.
정점 번호를 키로 하여 연결된 정점 리스트를 저장합니다.

int[] color: 각 정점의 색을 저장합니다. 0은 색칠 안 된 상태, 1과 2는 각각의 색을 나타냅니다.

메인 메서드

– 입력으로 그래프의 정점 수와 간선 수를 받고, 이를 기반으로 그래프를 생성합니다.

– 모든 정점을 순회하며, BFS를 호출하여 이분 그래프 여부를 확인합니다.
주어진 모든 정점에 대해 확인 후 결과를 출력합니다.

DFS 메서드

– BFS 메서드는 큐를 기반으로 너비 우선 탐색을 수행합니다.
시작 정점을 색칠하고, 인접한 정점이 색칠되지 않았다면 현재 정점과 다른 색으로 색칠합니다.

– 이미 색칠된 정점이 현재 정점과 같은 색으로 색칠되어 있다면 이분 그래프가 아니므로 false를 반환합니다.

6. 복잡도 분석

본 알고리즘의 시간복잡도는 O(V + E)입니다.
V는 정점의 수, E는 간선의 수이며, 그래프의 모든 정점과 간선을 탐색하기 때문입니다.
따라서 주어진 입력 크기에 대해 효율적으로 작동할 수 있습니다.

7. 결론

이 글에서는 이분 그래프의 정의와 이를 판별하는 문제를 C#으로 해결하는 방법에 대해 설명했습니다.
그래프 이론의 기초와 BFS/DFS 알고리즘을 익히고, 이를 실전에 활용하는 데 도움이 되었기를 바랍니다.
또한, 다양한 문제를 풀어보며 그래프 알고리즘에 대한 이해를 높여가길 바랍니다.

8. 추가 참고자료

C# 코딩테스트 강좌, 최솟값 찾기 1

코딩 테스트에서 알고리즘 문제는 다양한 데이터 구조와 알고리즘을 이해하고 응용할 수 있는 매우 중요한 기회를 제공합니다. 이번 강좌에서는 최솟값을 찾는 문제를 다루며, 이를 C# 언어로 해결하는 과정을 자세히 설명하겠습니다.

문제 설명

다음과 같은 배열이 주어졌을 때, 배열의 최솟값을 찾는 프로그램을 작성하시오. 최솟값을 찾는 알고리즘을 구현하고, 해당 알고리즘의 시간 복잡도와 공간 복잡도를 분석하는 것도 포함됩니다.

문제

주어진 정수 배열에서 최솟값을 찾아 반환하시오.

입력: 
[3, 5, 1, 8, 2, 0, -3, 7]

출력:
-3

문제 분석

이 문제는 매우 직관적이며 단순하지만, 배열 내에서 최솟값을 찾는 과정은 여러 가지 방법으로 접근할 수 있습니다. 기본적으로, 배열의 길이를 n이라고 했을 때, 최솟값을 찾기 위해 배열을 한 번 스캔하려면 O(n)의 시간이 소요됩니다.

해결 방안

이 문제를 해결하기 위한 기본적인 알고리즘은 다음과 같습니다.

  1. 배열의 첫 번째 요소를 초기 최솟값으로 설정합니다.
  2. 배열의 모든 요소를 하나씩 비교하여 현재의 최솟값보다 작은 경우, 최솟값을 업데이트합니다.
  3. 모든 요소를 확인한 후 최솟값을 반환합니다.

C# 코드 구현

이제 위의 알고리즘을 구현한 C# 코드를 살펴보겠습니다.

using System;

class Program
{
    static void Main()
    {
        int[] numbers = { 3, 5, 1, 8, 2, 0, -3, 7 };
        int minValue = FindMinimum(numbers);
        Console.WriteLine("최솟값: " + minValue);
    }

    static int FindMinimum(int[] array)
    {
        // 첫 번째 요소를 초기 최솟값으로 설정
        int min = array[0];

        // 배열을 한 번 순회하며 최솟값을 찾음
        for (int i = 1; i < array.Length; i++)
        {
            if (array[i] < min)
            {
                min = array[i];
            }
        }
        return min;
    }
}

코드 설명

위 코드는 C# 언어로 배열의 최솟값을 찾기 위한 프로그램입니다. 아래는 코드의 각 부분에 대한 설명입니다:

  • using System;
    C#에서 기본적인 기능을 사용하기 위해 필요한 네임스페이스입니다.
  • class Program
    메인 클래스를 정의하며, 프로그램의 시작점을 제공합니다.
  • static void Main()
    프로그램의 메인 실행 진입점으로, 이곳에서 최솟값을 찾기 위한 메서드를 호출합니다.
  • int[] numbers = { 3, 5, 1, 8, 2, 0, -3, 7 };
    최솟값을 찾고자 하는 정수 배열을 초기화합니다.
  • int minValue = FindMinimum(numbers);
    FindMinimum 메서드를 호출하여 배열의 최솟값을 찾습니다.
  • Console.WriteLine(“최솟값: ” + minValue);
    찾은 최솟값을 콘솔에 출력합니다.
  • static int FindMinimum(int[] array)
    최솟값을 찾기 위한 메서드로, 배열을 파라메터로 받습니다.
  • int min = array[0];
    배열의 첫 번째 요소를 초기 최솟값으로 설정합니다.
  • for (int i = 1; i < array.Length; i++)
    배열의 나머지 요소를 순회하면서 현재의 최솟값과 비교합니다.
  • if (array[i] < min)
    현재 요소가 최솟값보다 작을 경우, 최솟값을 업데이트합니다.

시간 복잡도 및 공간 복잡도 분석

알고리즘의 시간 복잡도는 O(n)입니다. 이는 배열을 한 번 순회하기 때문으로, 배열의 요소 수에 비례하여 시간이 소요됩니다. 공간 복잡도는 O(1)입니다. 이는 추가적인 데이터 구조를 사용하지 않고, 상수 개수의 변수만을 사용하기 때문입니다.

알고리즘의 활용 예

최솟값을 찾는 알고리즘은 다양한 분야에서 활용될 수 있습니다. 예를 들어:

  • 통계학에서 데이터 집합의 최솟값을 찾는 데 사용됩니다.
  • 리스트에서 특정 조건을 만족하는 최소값을 찾아야 할 경우 유용합니다.
  • 게임 개발에서 특정 객체의 위치나 속성의 한계를 정할 때 필요할 수 있습니다.

결론

C#을 사용하여 기본적인 최솟값 찾기 알고리즘을 구현했습니다. 대부분의 코딩 테스트에서는 이와 같은 기본적인 문제를 통해 문제 해결 능력을 평가하며, 다양한 방식으로 이 문제를 확장할 수 있습니다. 이 강좌를 통해 최솟값을 찾는 개념을 확립하고, 이를 다양한 방식으로 응용할 수 있는 능력을 기르시길 바랍니다.

앞으로의 강좌에서도 다양한 알고리즘 문제를 다룰 예정이니, 많은 관심 부탁드립니다.

C# 코딩테스트 강좌, 벨만-포드

흔히 알고리즘 문제를 풀다 보면 다양한 최단 경로 문제를 마주하게 됩니다. 그 중에서도 “벨만-포드 알고리즘”은 음수 가중치 간선을 포함한 그래프에서 최단 경로를 찾는 데 유용한 알고리즘입니다. 이번 강좌에서는 벨만-포드 알고리즘에 대해 깊이 이해하고, 이를 활용한 문제를 하나 해결해 보도록 하겠습니다.

벨만-포드 알고리즘 소개

벨만-포드 알고리즘은 주어진 그래프에서 출발점에서 모든 정점까지의 최단 경로를 찾는 알고리즘입니다. 이 알고리즘은 다음과 같은 특징을 가지고 있습니다:

  • 음수 가중치를 갖는 간선이 있는 그래프에서도 최단 경로를 찾을 수 있습니다.
  • 음수 사이클이 존재하면, 최단 경로는 정의할 수 없습니다.
  • 시간 복잡도는 O(VE)입니다. 여기서 V는 정점의 수, E는 간선의 수입니다.

벨만-포드 알고리즘의 동작 원리

이 알고리즘은 다음과 같은 방법으로 동작합니다:

  1. 모든 정점의 거리 값을 무한대로 초기화합니다. 단, 시작 정점의 거리 값은 0으로 설정합니다.
  2. 모든 간선에 대해서, 해당 간선을 통해 이동할 수 있는 경우 거리 값을 업데이트합니다.
  3. 이 과정을 V – 1번 반복합니다. 왜냐하면 최장 경로는 V – 1개의 간선으로 이루어질 수 있기 때문입니다.
  4. 마지막으로, 음수 사이클이 존재하는지 확인하기 위해 한 번 더 모든 간선을 검사합니다.

문제 설명

문제: 최단 경로 찾기

주어진 그래프의 정점 N과 간선 M이 주어집니다. 시작 정점 S에서 다른 모든 정점까지의 최단 경로를 구하시오. 음수 가중치 간선이 있을 수 있으며, 음수 사이클이 존재할 경우 “Negative Cycle”를 출력합니다.

입력
3 3 1
1 2 2
1 3 3
2 3 -5

출력
1 0 2

입력 예시 설명

위 입력 예시는 다음과 같은 그래프를 나타냅니다:

정점 수: 3

간선 수: 3

시작 정점: 1

  • 1 ↔ 2 : 가중치 2
  • 1 ↔ 3 : 가중치 3
  • 2 ↔ 3 : 가중치 -5

코드 구현

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // 입력 받기
        string[] input = Console.ReadLine().Split();
        int N = int.Parse(input[0]); // 정점 수
        int M = int.Parse(input[1]); // 간선 수
        int S = int.Parse(input[2]); // 시작 정점

        // 그래프 초기화
        List> edges = new List>();
        for (int i = 0; i < M; i++)
        {
            input = Console.ReadLine().Split();
            int u = int.Parse(input[0]); // 시작 정점
            int v = int.Parse(input[1]); // 도착 정점
            int w = int.Parse(input[2]); // 가중치
            edges.Add(Tuple.Create(u, v, w));
        }

        // 거리 배열 초기화
        int[] distance = new int[N + 1];
        Array.Fill(distance, int.MaxValue);
        distance[S] = 0;

        // 벨만-포드 알고리즘
        for (int i = 1; i <= N - 1; i++)
        {
            foreach (var edge in edges)
            {
                int u = edge.Item1;
                int v = edge.Item2;
                int w = edge.Item3;
                if (distance[u] != int.MaxValue && distance[u] + w < distance[v])
                {
                    distance[v] = distance[u] + w;
                }
            }
        }

        // 음수 사이클 체크
        bool hasNegativeCycle = false;
        foreach (var edge in edges)
        {
            int u = edge.Item1;
            int v = edge.Item2;
            int w = edge.Item3;
            if (distance[u] != int.MaxValue && distance[u] + w < distance[v])
            {
                hasNegativeCycle = true;
                break;
            }
        }

        // 결과 출력
        if (hasNegativeCycle)
        {
            Console.WriteLine("Negative Cycle");
        }
        else
        {
            for (int i = 1; i <= N; i++)
            {
                Console.WriteLine(distance[i] == int.MaxValue ? "INF" : distance[i].ToString());
            }
        }
    }
}

코드 설명

위 코드는 벨만-포드 알고리즘을 구현한 것입니다. 코드의 주요 부분을 설명하겠습니다.

  • List<Tuple<int, int, int>> edges: 간선 정보를 저장하기 위한 리스트입니다.
  • int[] distance: 각 정점까지의 최단 거리를 저장합니다. 초기값은 무한대로 설정하고, 시작 정점의 거리는 0으로 초기화합니다.
  • 벨만-포드 알고리즘의 핵심인 반복문에서 각 간선을 검사하며 거리를 업데이트합니다.
  • 마지막에는 음수 사이클이 존재하는지 확인하기 위해 한 번 더 간선을 검사합니다.

결론

이번 강좌를 통해 벨만-포드 알고리즘의 개념과 이를 활용한 문제를 해결하는 과정을 살펴보았습니다. 알고리즘의 원리를 깊이 이해하고 이를 코드로 구현하는 과정을 통해 코딩테스트에서의 응용 능력을 키울 수 있습니다.

벨만-포드 알고리즘은 실무에서도 여러 가지 최단 경로 문제를 해결하는 데 사용되므로, 이를 충분히 이해하고 연습하여 코딩테스트에 대비하시기 바랍니다.