자바 코딩테스트 강좌, 효율적으로 해킹하기

안녕하세요! 오늘은 자바를 이용한 코딩테스트 강좌를 통해 알고리즘 문제를 풀어봤습니다. 특히 ‘해킹’이 주제가 되는 문제를 소개하고, 이를 해결하는 과정을 단계별로 설명하겠습니다. 이 강좌는 자바 언어를 주로 사용하는 사람들을 대상으로 하며, 알고리즘 문제 풀이 능력을 향상시키기 위한 내용을 포함하였습니다.

문제 설명

문제의 제목: 해커의 비밀번호

해커가 작은 회사의 서버에 침입하기 위해 비밀번호를 알아내려고 합니다. 다행히도 해커는 일련의 이전 비밀번호들을 알고 있습니다. 이 비밀번호들은 서로 다른 알파벳 문자로 이루어져 있습니다. 해커는 비밀번호를 추측하기 위해 ‘가장 많이 사용된 알파벳’을 찾아내야 합니다.

문제 정의

입력: 
- N (1 ≤ N ≤ 1000): 비밀번호의 개수
- 비밀번호: 길이는 최대 50이며, 알파벳 소문자로만 이루어져 있음.

출력: 
가장 많이 사용된 알파벳과 그 개수를 "알파벳: 개수" 형식으로 출력

예제 입력

5
abcde
fghij
klmno
abcfg
hijkl

예제 출력

a: 2
b: 2
c: 2
f: 2
g: 2
h: 2
i: 2
j: 2
k: 2
l: 2
m: 1
n: 1
o: 1

문제 풀이 접근법

이 문제를 해결하기 위해 다음과 같은 접근 방법을 고려하였습니다.

1단계: 문제 이해 및 분석

주어진 문제는 각 비밀번호 안에 등장하는 알파벳의 빈도를 세고, 가장 많이 등장한 알파벳을 출력하는 것입니다. 입력 개수와 각 비밀번호의 특징을 고려할 때, 이 문제는 알고리즘적으로 카운팅(Counting) 방법이 적합할 것입니다. 카운팅을 통해 각 알파벳의 빈도를 세는 구조를 구현할 수 있습니다.

2단계: 데이터 구조 설계

알파벳의 빈도를 저장하기 위해 HashMap을 사용할 것입니다. HashMap은 키-값 쌍으로 데이터를 저장하며, 키는 알파벳 문자(‘a’~‘z’)이고 값은 해당 알파벳의 빈도수입니다. 이 구조를 통해 각 비밀번호를 순회하며 빈도를 계산할 수 있습니다.

3단계: 알고리즘 설계

1. HashMap을 생성하여 알파벳의 개수를 저장합니다.
2. 입력으로 주어진 비밀번호를 순회합니다.
3. 각각의 비밀번호를 다시 순회하며 알파벳을 카운트합니다.
4. 다음과 같은 형식으로 결과 출력합니다: "알파벳: 개수".

자바 코드 구현

이제 알고리즘은 정해졌으니, 이를 자바 코드로 구현해보겠습니다.


import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class HackerPassword {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        scanner.nextLine(); // 버퍼 비우기

        Map frequencyMap = new HashMap<>();
        
        // 비밀번호 입력 및 카운팅
        for (int i = 0; i < n; i++) {
            String password = scanner.nextLine();
            for (char c : password.toCharArray()) {
                frequencyMap.put(c, frequencyMap.getOrDefault(c, 0) + 1);
            }
        }

        // 결과 출력
        for (Map.Entry entry : frequencyMap.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
    }
}

코드 설명

위의 코드를 단계별로 살펴보겠습니다:

  • 입력 처리: 먼저 Scanner 클래스를 이용해 비밀번호 개수 n을 입력받고, 이후 비밀번호를 입력받습니다.
  • HashMap 초기화: HashMap을 초기화하여 각 알파벳의 등장 빈도를 기록합니다.
  • 빈도 카운팅: 이중 for 루프를 사용하여 각 비밀번호를 문자열로 받아서 문자 하나씩 HashMap에 카운트합니다. getOrDefault 메소드를 사용해 기본값 0을 설정하여 카운팅을 처리합니다.
  • 결과 출력: 최종적으로 HashMap을 순회하여 알파벳과 그 빈도를 출력합니다.

테스트 및 검증

작성한 알고리즘과 코드를 다양한 테스트 케이스로 검증해야 합니다. 주어진 조건에 따라 여러 비밀번호를 입력해도 정상적으로 각 알파벳의 빈도를 출력하는지 확인합니다. 예를 들어:

테스트 케이스 1

입력:
3
aaa
bbb
c

출력:
a: 3
b: 3
c: 1

테스트 케이스 2

입력:
4
abcd
efgh
ijkl
mnop

출력:
a: 1
b: 1
c: 1
d: 1
e: 1
f: 1
g: 1
h: 1
i: 1
j: 1
k: 1
l: 1
m: 1
n: 1
o: 1
p: 1

각 테스트 케이스에 대해 예상된 결과와 실제 출력을 비교함으로써 코드의 정확성을 검증할 수 있습니다.

마무리

오늘의 강좌에서는 비밀번호를 해킹하기 위해 알파벳의 빈도를 카운트하는 알고리즘 문제를 다루어 보았습니다. 이러한 알고리즘 문제는 코딩테스트에서 빈번하게 나타나는 유형이며, 다양한 변형이 존재합니다. 이 강좌를 통해 알고리즘 문제를 접근하는 방법을 배웠길 바라며, 자바 프로그래밍 언어를 깊게 이해하는 데 도움이 되었으면 합니다.

다음 시간에는 더 복잡한 알고리즘 문제를 소개하고, 최적화 기법에 대해서도 다룰 예정입니다. 끝까지 읽어주셔서 감사합니다!

자바 코딩테스트 강좌, 회의실 배정하기

프로그래밍 면접 준비를 하는 과정에서, 특정 알고리즘 문제를 해결하는 것은 매우 중요합니다. 오늘은 ‘회의실 배정하기’라는 주제로 자바로 문제를 해결해보겠습니다. 이 문제는 알고리즘과 자료구조를 이해하는 데 도움을 주며, 특정 조건을 만족하는 최적의 해답을 찾는 데 초점을 맞추고 있습니다.

문제 설명

다양한 회의들이 특정 시간 간격에 발생합니다. 각 회의는 시작 시간과 끝 시간을 가집니다. 목표는 모든 회의를 가능한 최소한의 회의실에서 할당하는 것입니다.

문제 정의

제목: 회의실 배정하기

입력:
- 여러 개의 회의가 주어질 때, 각 회의는 시작 시간과 끝 시간으로 정의됨 (start, end).
- 회의는 [[start1, end1], [start2, end2], ...] 형태로 주어짐.

출력:
- 회의실의 개수를 최소화하여 회의실을 배정했을 때 필요한 회의실의 수를 반환하시오.

예제 입력 및 출력

입력: [[0, 30], [5, 10], [15, 20]]
출력: 2  (회의실 2개 필요)

입력: [[7, 10], [2, 4]]
출력: 1  (회의실 1개 필요)

해결 접근법

이 문제를 해결하기 위해, 우리는 회의의 시작 시간을 기준으로 정렬하고, 우선순위 큐를 사용하여 현재 사용 중인 회의실의 종료 시간을 관리할 수 있습니다. 그 후, 각 회의를 순차적으로 확인하면서 새로운 회의실을 추가할지 여부를 결정합니다.

알고리즘 단계

  1. 회의를 시작 시간을 기준으로 오름차순으로 정렬합니다.
  2. 우선순위 큐를 사용하여 회의실의 종료 시간을 관리합니다.
  3. 각 회의를 확인하면서 종료 시간이 가장 빠른 회의실에 회의를 추가하거나 새로운 회의실을 할당합니다.
  4. 최종적으로 사용한 회의실의 개수를 반환합니다.

자바 코드 구현

아래는 위의 접근법을 바탕으로 구현한 자바 코드입니다:


import java.util.Arrays;
import java.util.PriorityQueue;

public class MeetingRooms {
    public int minMeetingRooms(int[][] intervals) {
        if (intervals.length == 0) {
            return 0;
        }

        // 회의를 시작 시간을 기준으로 정렬합니다.
        Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0]));

        // 우선순위 큐를 사용하여 회의실의 종료 시간을 관리합니다.
        PriorityQueue minHeap = new PriorityQueue<>();

        for (int[] interval : intervals) {
            // 현재 회의의 시작 시간과 가장 빠른 회의실의 종료 시간을 비교
            if (!minHeap.isEmpty() && interval[0] >= minHeap.peek()) {
                minHeap.poll(); // 회의실을 해제
            }
            // 새 회의실이 필요하다면 종료 시간 추가
            minHeap.add(interval[1]);
        }

        // 사용된 회의실의 수 반환
        return minHeap.size();
    }

    public static void main(String[] args) {
        MeetingRooms meetingRooms = new MeetingRooms();
        int[][] intervals = {{0, 30}, {5, 10}, {15, 20}};
        System.out.println("필요한 회의실의 수: " + meetingRooms.minMeetingRooms(intervals));

        int[][] intervals2 = {{7, 10}, {2, 4}};
        System.out.println("필요한 회의실의 수: " + meetingRooms.minMeetingRooms(intervals2));
    }
}

결과 및 시간 복잡도

위의 코드를 실행하면 주어진 회의에 필요한 회의실의 수를 정확히 계산할 수 있습니다. 이 알고리즘의 시간 복잡도는 다음과 같습니다:

  • 회의를 정렬하는 데 O(n log n)의 시간이 걸립니다.
  • 각 회의를 확인하면서 우선순위 큐에 추가하거나 제거하는 데 O(n log k)의 시간이 걸립니다.

그 결과, 전체 시간 복잡도는 O(n log n + n log k)로 분석할 수 있습니다. 여기서 n은 회의의 수, k는 사용 중인 회의실의 개수입니다.

마무리

이번 글에서는 ‘회의실 배정하기’ 문제를 해결하기 위한 접근법과 자바 코드 구현을 자세히 살펴보았습니다. 코딩 테스트 준비에 많은 도움이 되었기를 바라며, 자료구조와 알고리즘을 통해 문제 풀이 능력을 더욱 강화하시기 바랍니다.

자바 코딩테스트 강좌, 행렬 곱 연산 횟수의 최솟값 구하기

코딩테스트는 다양한 알고리즘 문제를 해결하는 능력을 평가하는 중요한 과정입니다. 특히, 행렬의 곱셈과 관련된 문제는 그 복잡성과 효율성을 고려했을 때, 많은 사람들이 어려워하는 주제 중 하나입니다. 이번 강좌에서는 “행렬 곱 연산 횟수의 최솟값 구하기”라는 문제를 통해 이를 자세히 다루어 보겠습니다.

문제 정의

두 개의 행렬 A(행렬 A는 m x n 크기)와 B(행렬 B는 n x p 크기)가 주어질 때, 이 두 행렬을 곱하는 데 필요한 연산 횟수를 최소화하려고 합니다. 연산 횟수는 각 행렬의 차원과 관련되어 있으며, 행렬 곱셈을 수행할 때 필요한 기본적인 연산은 다음과 같습니다:

  • A의 한 행과 B의 한 열을 곱하고 그 결과를 더하는 연산을 수행합니다.

즉, A의 행 수를 m, B의 열 수를 p, 그리고 A의 열 수 또는 B의 행 수를 n이라고 할 때, 한 번의 행렬 곱셈 연산의 연산 횟수는 m * n * p입니다. 우리는 여러 개의 행렬을 곱할 때 이 연산 횟수를 최소화하는 방법을 찾고자 합니다.

구현해야 할 문제

예를 들어, 다음과 같은 행렬들이 있을 때:

  • 행렬 A: 10 x 30
  • 행렬 B: 30 x 5
  • 행렬 C: 5 x 60

AB를 먼저 곱한 후 C와 곱하는 것이나, AC를 먼저 곱한 후 B와 곱하는 것은 결과가 같지만, 연산 횟수는 다를 수 있습니다. 따라서 최적의 순서를 찾아야 합니다.

해법

이 문제를 해결하기 위해 동적 프로그래밍(Dynamic Programming) 기술을 사용할 수 있습니다. 여러 개의 행렬이 주어졌을 때, 각 행렬 곱셈 순서를 고려하면서 최소 연산 횟수를 계산하는 방식입니다.

알고리즘 설명

  1. 행렬의 차원 정보를 배열에 저장합니다.
  2. 동적 프로그래밍 배열을 생성하여 각 부분 문제의 최적 해를 저장합니다.
  3. 각 행렬 곱셈의 순서를 계산하여 최소 연산 횟수를 구합니다.

구체적으로 다음과 같은 단계를 따릅니다:

  • 풀이할 행렬의 크기를 char 배열로 저장합니다. 예를 들어, {10, 30, 5, 60}이라면, 이를 통해 10×30, 30×5, 5×60 형태의 행렬을 정의합니다.
  • 각 부분 행렬을 곱하는 데 필요한 최소 연산 횟수를 구하기 위해 2차원 배열을 사용하여 저장합니다.
  • 문제를 재귀적으로 나누어 해결하며, 기존에 계산했던 값을 재사용하는 방식으로 효율성을 높입니다.

자바로 구현하기


public class MatrixChainMultiplication {
    static int[][] dp;
    static int[] dims;

    public static void main(String[] args) {
        // 행렬 차원 입력
        dims = new int[] {10, 30, 5, 60}; // (10x30) * (30x5) * (5x60)

        int n = dims.length - 1;
        dp = new int[n][n];

        // 행렬 곱셈 최소 연산 횟수 계산
        System.out.println("최소 연산 횟수: " + calculateMinOperations(0, n - 1));
    }

    public static int calculateMinOperations(int i, int j) {
        // 기저 사례: 단일 행렬은 연산이 필요 없다.
        if (i == j) {
            return 0;
        }

        // 이미 계산된 경우 반환
        if (dp[i][j] != 0) {
            return dp[i][j];
        }

        dp[i][j] = Integer.MAX_VALUE;

        // 서로 다른 두 행렬 곱셈 조합에 대해 최적 연산 횟수 계산
        for (int k = i; k < j; k++) {
            int operations = calculateMinOperations(i, k) + calculateMinOperations(k + 1, j) + dims[i] * dims[k + 1] * dims[j + 1];

            // 최소 연산 횟수 업데이트
            dp[i][j] = Math.min(dp[i][j], operations);
        }

        return dp[i][j];
    }
}

성능 분석

이 알고리즘은 O(n^3)의 시간 복잡도를 가집니다. 여기서 n은 행렬의 개수입니다. 이는 각 부분 문제를 O(n^2)로 접근하면서, 각 두 부분 문제 간의 행렬 곱 연산을 고려해야 하므로 발생하는 복잡성입니다. 이러한 알고리즘은 최적화된 방법으로 주어진 입력에 대해 효율적입니다.

결론

이번 강좌를 통해 행렬 곱셈 문제의 최적화 방법, 동적 프로그래밍을 통한 접근 방식, 자바 구현 방법 등을 살펴보았습니다. 이러한 문제는 실제 프로그래밍에 자주 등장하기 때문에, 충분히 연습하고 익혀 두는 것이 중요합니다. 특히 코딩테스트와 같은 곳에서 자주 볼 수 있는 유형이므로, 이 강좌에서 다룬 내용을 잘 숙지하시기 바랍니다.

관련 자료가 필요하시거나 질문이 있으시면 댓글로 남겨 주시길 바랍니다. 감사합니다!

자바 코딩테스트 강좌, 확장 유클리드 호제법

본 강좌에서는 확장 유클리드 호제법(Extended Euclidean Algorithm)에 대해 자세히 알아보고, 이를 활용한 알고리즘 문제를 해결해 보겠습니다. 확장 유클리드 호제법은 두 정수 ab의 최대공약수(gcd)를 구하고, 또한 ax + by = gcd(a, b) 형태의 정수 해를 구하는 데 사용됩니다. 이 기법은 현대 암호학에서도 널리 사용됩니다.

문제 설명

다음 문제를 해결해 보겠습니다.

문제

두 정수 ab가 주어질 때, ax + by = gcd(a, b)의 해인 x, y를 찾고 이 값을 출력하시오.

알고리즘의 이해

확장 유클리드 호제법은 기본 유클리드 알고리즘을 바탕으로 하여, gcd(a, b)를 구하고 이를 이용하여 계수 x, y를 계산할 수 있도록 합니다. 기본적인 유클리드 알고리즘은 두 수의 최대공약수를 구하는 알고리즘으로, 다음과 같은 재귀적 과정을 따릅니다:

    gcd(a, 0) = a
    gcd(0, b) = b
    gcd(a, b) = gcd(b, a mod b)
    

확장 유클리드 호제법

확장 유클리드 호제법에서는 더욱 더 발전된 접근을 합니다. 앞서 언급한 것처럼, 두 정수의 최대공약수는 단순히 그 값을 구하는 것뿐만 아니라 두 수의 정수 계수까지 도출합니다. 기본 아이디어는 다음과 같습니다:

  1. 유클리드 알고리즘을 사용하여 gcd(a, b)를 재귀적으로 계산합니다.
  2. 각 단계에서의 xy 값을 추적하면서 필요한 경우 업데이트합니다.

재귀적 접근

    1. 먼저, gcd(a, b)를 구한 후에,
    2. x = y1 - (a / b) * x1
    3. y = x1로 업데이트합니다.
    

문제 풀이 과정

자바 구현

이제 자바를 사용하여 위의 알고리즘을 구현해 보겠습니다. 아래의 코드는 두 정수 ab를 입력으로 받고, gcd(a, b)x, y를 출력하는 프로그램입니다.

    
    public class ExtendedEuclidean {
        static int[] extendedGcd(int a, int b) {
            if (b == 0) {
                return new int[] { a, 1, 0 };
            }
            int[] recResult = extendedGcd(b, a % b);
            int gcd = recResult[0];
            int x1 = recResult[1];
            int y1 = recResult[2];
            int x = y1;
            int y = x1 - (a / b) * y1;
            return new int[] { gcd, x, y };
        }

        public static void main(String[] args) {
            int a = 30; // 입력으로 사용할 첫 번째 수
            int b = 12; // 입력으로 사용할 두 번째 수
            int[] result = extendedGcd(a, b);
            System.out.println("GCD: " + result[0]);
            System.out.println("x: " + result[1]);
            System.out.println("y: " + result[2]);
        }
    }
    
    

코드 설명

위의 코드에서 extendedGcd 메서드는 재귀적으로 최대공약수(limit)와 해당 계수 x, y를 반환합니다. 기본적으로, 만약 b가 0이면 gcd(a, 0) = a이므로 이를 반환합니다. 그렇지 않으면, gcd(b, a % b) 비율을 이용하여 재귀적으로 값을 구합니다.

테스트와 결과

이제 위의 코드를 실행하여 입력값을 조정해 보겠습니다. 우리는 다음과 같은 다양한 입력 예제를 고려할 수 있습니다:

테스트 케이스

  • a = 30, b = 12
  • a = 56, b = 15
  • a = 101, b = 10

각 경우에 대한 결과를 확인해 봅시다.

결과 예시

예제 1: a = 30, b = 12

GCD: 6

x: 1, y: -2

예제 2: a = 56, b = 15

GCD: 1

x: -4, y: 15

예제 3: a = 101, b = 10

GCD: 1

x: 1, y: -10

결론

이번 강좌에서는 확장 유클리드 호제법의 기본적 이론과 이를 활용한 문제 해결 접근 방법에 대해 알아보았습니다. 이를 통해 여러분들은 수학적 기초와 함께 자바 프로그래밍 실력을 함께 향상시킬 수 있었기를 바랍니다. 추가적으로, 다양한 입력값에 대해 구현 및 테스트를 진행하면서 알고리즘에 대한 이해도를 높여볼 수 있길 바랍니다.

추가 학습 자료

확장 유클리드 호제법에 대한 더 많은 정보는 아래의 링크를 통해 참고하시기 바랍니다.

자바 코딩테스트 강좌, 플로이드-워셜

안녕하세요! 이번 강좌에서는 자바 코딩테스트에서 자주 출제되는 플로이드-워셜 알고리즘에 대해 배워보도록 하겠습니다. 플로이드-워셜 알고리즘은 모든 지점에서 다른 모든 지점까지의 최단 경로를 찾는 데 효율적인 방법입니다. 특히, 그래프의 정점 수가 적은 경우 유용하게 사용됩니다. 이번 글에서는 플로이드-워셜 알고리즘을 적용한 문제를 풀어보며, 그 과정을 자세히 설명하겠습니다.

문제 설명

다음은 플로이드-워셜 알고리즘을 활용한 문제입니다.

문제: 주어진 N개의 도시와 도시 간의 도로 정보를 이용하여, 모든 도시 간의 최단 경로를 구하시오. 
각 도시는 1부터 N까지 번호가 붙어 있으며, 도로는 양방향으로 연결되어 있습니다. 
도로 정보는 다음과 같은 형식으로 주어집니다: 

N  M
x y z 

여기서 N은 도시의 수, M은 도로의 수, x는 도로의 한 쪽 도시, y는 도로의 다른 쪽 도시, z는 두 도시 간의 거리입니다. 
자신과의 거리(예: 1번 도시에서 1번 도시까지의 거리)는 항상 0으로 설정되어 있습니다. 
두 도시 간의 직접적인 도로가 여러 개 있을 경우, 거리 값이 가장 작은 도로 정보만을 고려합니다.

입력 예시:
4 7
1 2 4
1 3 2
2 3 5
2 4 10
3 4 3
1 4 8
3 1 3

출력 예시:
0 2 3 5
2 0 5 3
3 5 0 3
5 3 3 0

문제 풀이 과정

이제 이 문제를 해결하기 위해 플로이드-워셜 알고리즘을 구현해 보겠습니다. 다음은 알고리즘을 단계별로 설명한 것입니다.

1. 데이터 구조 설정

먼저, 모든 도시 간의 거리 정보를 저장할 2차원 배열을 설정합니다. N개의 도시가 있으므로 배열의 크기는 dist[N + 1][N + 1]으로 합니다. 배열의 모든 요소는 초기값으로 무한대(Integer.MAX_VALUE)로 설정합니다. 그러나 각 도시에서 자신까지의 거리는 0으로 설정합니다.

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

for (int i = 1; i <= N; i++) {
    Arrays.fill(dist[i], Integer.MAX_VALUE);
    dist[i][i] = 0;
}

2. 도로 정보를 입력받아 거리 배열 초기화

입력받은 도로 정보를 통해 각 도시 간의 거리 정보를 설정합니다. 만약 두 도시 간에 여러 개의 도로가 주어진 경우, 거리 배열에는 가장 짧은 거리만 저장합니다.

for (int i = 0; i < M; i++) {
    int x = sc.nextInt();
    int y = sc.nextInt();
    int z = sc.nextInt();
    dist[x][y] = Math.min(dist[x][y], z);
    dist[y][x] = Math.min(dist[y][x], z);
}

3. 플로이드-워셜 알고리즘 구현

플로이드-워셜 알고리즘의 핵심은 삼중 루프를 통해 모든 짝의 최단 거리를 반복적으로 업데이트하는 것입니다. 아래는 플로이드-워셜 알고리즘의 구현 코드입니다.

for (int k = 1; k <= N; k++) {
    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= N; j++) {
            if (dist[i][j] > dist[i][k] + dist[k][j]) {
                dist[i][j] = dist[i][k] + dist[k][j];
            }
        }
    }
}

4. 결과 출력

마지막으로 모든 도시 간의 최단 경로를 출력합니다. 1번 도시부터 N번 도시까지의 거리를 차례대로 출력합니다.

for (int i = 1; i <= N; i++) {
    for (int j = 1; j <= N; j++) {
        if (dist[i][j] == Integer.MAX_VALUE) {
            System.out.print("INF ");
        } else {
            System.out.print(dist[i][j] + " ");
        }
    }
    System.out.println();
}

전체 코드

이제 위의 모든 과정을 하나의 자바 프로그램으로 통합해 보겠습니다. 아래는 문제를 해결하기 위한 전체 자바 코드입니다.

import java.util.Arrays;
import java.util.Scanner;

public class FloydWarshall {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt(); // 도시의 수
        int M = sc.nextInt(); // 도로의 수

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

        // 초기화
        for (int i = 1; i <= N; i++) {
            Arrays.fill(dist[i], Integer.MAX_VALUE);
            dist[i][i] = 0; // 자기 자신과의 거리는 0
        }

        // 도로 정보 입력
        for (int i = 0; i < M; i++) {
            int x = sc.nextInt();
            int y = sc.nextInt();
            int z = sc.nextInt();
            dist[x][y] = Math.min(dist[x][y], z);
            dist[y][x] = Math.min(dist[y][x], z);
        }

        // 플로이드-워셜 알고리즘
        for (int k = 1; k <= N; k++) {
            for (int i = 1; i <= N; i++) {
                for (int j = 1; j <= N; j++) {
                    if (dist[i][j] > dist[i][k] + dist[k][j]) {
                        dist[i][j] = dist[i][k] + dist[k][j];
                    }
                }
            }
        }

        // 결과 출력
        for (int i = 1; i <= N; i++) {
            for (int j = 1; j <= N; j++) {
                if (dist[i][j] == Integer.MAX_VALUE) {
                    System.out.print("INF ");
                } else {
                    System.out.print(dist[i][j] + " ");
                }
            }
            System.out.println();
        }
    }
}

정리

이번 강좌에서는 플로이드-워셜 알고리즘을 이용하여 도시 간의 최단 경로를 구하는 문제를 해결해 보았습니다. 이 알고리즘은 모든 쌍의 최단 경로를 구하는 데 유용하게 사용할 수 있으며, 코드의 구조와 로직을 이해하는 데 큰 도움이 되었을 것입니다. 실제 코딩테스트에서는 이러한 알고리즘을 활용하여 효율적인 문제 해결 능력을 키우는 것이 중요합니다.

참고: 플로이드-워셜 알고리즘의 시간 복잡도는 O(N^3)이므로, 그래프의 정점 수가 많을 경우 다른 최단 경로 알고리즘(예: 다익스트라 알고리즘)을 고려하는 것이 좋습니다.

앞으로도 알릴루야 코딩테스트 강좌에서 다양한 알고리즘을 소개하겠습니다. 감사합니다!