C++ 코딩테스트 강좌, K번째 수 구하기

안녕하세요! 이번 글에서는 C++을 이용한 코딩테스트 문제 중 하나인 “K번째 수 구하기”에 대해 다뤄보겠습니다. 쿠폰 픽업과 같이 실생활에서도 한 번쯤은 고민해본 K번째 수 구하기 문제는 알고리즘 문제풀이에서 자주 접할 수 있는 문제 중 하나입니다. 이번 포스트에서는 문제 정의부터 풀이 과정, C++ 코드 구현까지 상세히 설명하겠습니다.

문제 정의

주어진 정수 배열이 있고, 이 배열에서 K번째로 작은 수를 찾는 문제입니다. 여기서 K는 1부터 시작하는 정수로, 첫 번째로 작은 수, 두 번째로 작은 수, …의 의미를 갖습니다.

예를 들어, 다음과 같은 입력을 고려해 봅시다:

배열: [3, 1, 2, 4, 5]
K: 3

주어진 배열에서 3번째로 작은 수는 3입니다. 따라서 이 경우의 정답은 3이 됩니다.

입력 형식

  • 첫 번째 줄: 배열의 길이 N (1 <= N <= 100,000)
  • 두 번째 줄: 정수 배열 A (1 <= A[i] <= 10^9)
  • 세 번째 줄: 정수 K (1 <= K <= N)

출력 형식

K번째로 작은 수를 출력합니다.

문제 풀이 계획

이 문제를 해결하기 위해 사용할 수 있는 몇 가지 알고리즘을 생각해 볼 수 있습니다.

  • 정렬: 배열을 정렬한 후 K번째 인덱스를 반환합니다.
  • 최소힙 사용: 힙을 사용해서 K번째로 작은 수를 찾아낼 수 있습니다.
  • 퀵 선택 알고리즘: 평균 O(N) 시간복잡도로 K번째 수를 찾을 수 있는 알고리즘입니다.

여기서는 가장 직관적이고 이해하기 쉬운 방법인 배열 정렬을 사용한 풀이를 구현해 보겠습니다.

구현하기

먼저 C++의 vector를 사용하여 배열을 입력받고, sort() 함수를 이용해 정렬하겠습니다. 그 후, K번째 수를 출력하는 방식으로 프로그램을 구성하겠습니다.

코드 구현

#include 
#include 
#include  // sort()의 사용을 위해 include
using namespace std;

int main() {
    int N, K;
    
    // 배열의 크기 N 입력
    cout << "배열의 길이 N을 입력하세요: ";
    cin >> N;

    vector A(N);
    
    // 배열 A 입력
    cout << "정수 배열 A를 입력하세요 (띄어쓰기로 구분): ";
    for(int i = 0; i < N; i++) {
        cin >> A[i];
    }
    
    // K 값 입력
    cout << "K 값을 입력하세요: ";
    cin >> K;

    // 배열 정렬
    sort(A.begin(), A.end());

    // K번째 수 출력 (인덱스는 K-1)
    cout << K << "번째 수는: " << A[K - 1] << endl;

    return 0;
}

코드 설명

이 코드는 다음과 같은 흐름으로 동작합니다:

  1. 사용자로부터 배열의 길이 N을 입력받습니다.
  2. N 길이의 정수 형 벡터 A를 생성합니다.
  3. 사용자로부터 배열 A의 원소를 입력받습니다.
  4. K 값을 입력받습니다.
  5. 배열 A를 오름차순으로 정렬합니다.
  6. K번째 수를 출력합니다. C++에서는 인덱스가 0부터 시작하므로 K-1을 사용해야 합니다.

코드 분석

문제의 입력은 최대 100,000개로, 최악의 경우 O(N log N)의 시간복잡도를 가진 정렬을 수행하게 됩니다. 정렬 후에는 K번째 수를 O(1) 시간에 찾을 수 있으므로, 전체 시간복잡도는 O(N log N)입니다. 이는 주어진 시간 제한 내에 충분히 해결할 수 있는 복잡도입니다.

테스트 케이스

위 코드를 검증하기 위해 몇 가지 테스트 케이스를 고려해 보겠습니다:

테스트 케이스 1

입력:
5
3 1 2 4 5
3
출력:
3번째 수는: 3

테스트 케이스 2

입력:
10
10 9 8 7 6 5 4 3 2 1
5
출력:
5번째 수는: 5

테스트 케이스 3

입력:
5
1 10000 500 999 1000
2
출력:
2번째 수는: 500

결과 및 최적화

기본적인 풀이를 구현해 보았습니다. 정렬을 사용한 방법은 직관적이며 구현이 용이하지만, 배열의 크기가 매우 클 경우 다른 방법이 필요할 수 있습니다. 예를 들어, 퀵 선택 알고리즘을 사용하는 방법이 있습니다. 퀵 선택 알고리즘은 평균적으로 O(N)의 성능을 가지며, 메모리가 제한된 경우 유용하게 사용될 수 있습니다.

퀵 선택 알고리즘 개요

퀵 선택 알고리즘은 분할 정복 알고리즘의 일종으로, 랜덤 피벗을 선택하여 배열을 두 부분으로 나누고 K번째 수가 어떤 부분에 있는지를 판별하여 해당 부분만 계속 찾는 방법입니다. 매우 큰 배열에서도 빠르게 K번째 수를 찾을 수 있습니다.

퀵 선택 구현 예시

#include <iostream>
#include <vector>
#include <cstdlib> // rand() 함수를 위해
using namespace std;

// 배열에서 K번째 수를 찾는 퀵 선택 알고리즘
int quickSelect(vector& A, int left, int right, int K) {
    if (left == right) return A[left];

    int pivotIndex = left + rand() % (right - left);
    int pivotValue = A[pivotIndex];

    // 피벗을 배열의 맨 끝으로 이동
    swap(A[pivotIndex], A[right]);
    int storeIndex = left;

    for (int i = left; i < right; i++) {
        if (A[i] < pivotValue) {
            swap(A[storeIndex], A[i]);
            storeIndex++;
        }
    }

    // 피벗을 자신의 위치로 이동
    swap(A[storeIndex], A[right]);

    if (K == storeIndex) return A[K];
    else if (K < storeIndex) return quickSelect(A, left, storeIndex - 1, K);
    else return quickSelect(A, storeIndex + 1, right, K);
}

int main() {
    int N, K;

    cout << "배열의 길이 N을 입력하세요: ";
    cin >> N;

    vector A(N);
    
    cout << "정수 배열 A를 입력하세요 (띄어쓰기로 구분): ";
    for(int i = 0; i < N; i++) {
        cin >> A[i];
    }

    cout << "K 값을 입력하세요: ";
    cin >> K;

    int result = quickSelect(A, 0, N - 1, K - 1);
    cout << K << "번째 수는: " << result << endl;

    return 0;
}

마무리

오늘은 C++을 이용하여 K번째 수를 찾는 문제를 해결하는 방법에 대해 알아보았습니다. 기본적인 방법으로는 배열을 정렬하여 K번째 수를 찾는 방법을 구현하였고, 더 효율적인 방법으로 퀵 선택 알고리즘에 대해서도 간략히 설명드렸습니다. 이러한 문제들은 코딩 테스트에서 자주 출제되므로 반복적으로 학습해 두는 것이 좋습니다. 이 문제를 통해 알고리즘의 기초적인 이해와 C++ 프로그래밍 능력을 키우는 데 도움이 되길 바랍니다.

독서 감사합니다! 추가적인 질문이 있으시면 댓글로 남겨주세요.

C++ 코딩테스트 강좌, DNA 비밀번호

1. 문제 정의

얼마 전 한 생물학자가 DNA 시퀀스를 통해 특정 비밀번호를 만들어야 하는 상황에 처했습니다. 이 DNA 시퀀스는 A, C, G, T의 4종류의 뉴클레오타이드로 구성됩니다. 이 비밀번호는 주어진 DNA 시퀀스 내에서 선택된 A, C, G, T의 조합으로 만들어집니다.

문제 설명

주어진 문자열 S에서 길이가 K인 모든 부분 문자열 중에서 각 뉴클레오타이드의 빈도가 최소인 부분 문자열을 찾고, 그 중에서 비밀번호의 개수를 알아내는 프로그램을 작성하시오. 만약 모든 빈도가 같다면 그 빈도가 최소인 부분 문자열 중 가장 작은 사전 순서의 문자열을 선택합니다. 문자열의 길이는 주어진 문자열보다 작거나 같아야 합니다.

입력

  • 첫 번째 줄에 DNA 문자열 S의 길이 N (1 ≤ N ≤ 100,000)이 주어진다.
  • 두 번째 줄에 정수 K (1 ≤ K ≤ N)가 주어진다.
  • 세 번째 줄에 S가 주어진다.

출력

유효한 비밀번호의 개수와 그 중 가장 작은 사전 순서의 비밀번호를 출력하시오.

2. 알고리즘 분석

이 문제를 해결하기 위해 우리는 슬라이딩 윈도우(Sliding Window) 기법을 사용할 것입니다. 이 기법은 특정 길이 K의 부분 문자열을 이동하면서 각 문자(A, C, G, T)의 빈도를 카운트하여 문제를 해결할 수 있게 해줍니다.

절차

  1. K 길이의 첫 부분 문자열을 선택하여 문자의 빈도를 카운트한다.
  2. 이후 슬라이딩 윈도우를 사용하여 문자열을 이동하면서 새로운 문자가 추가될 때와 빠질 때 빈도를 조정한다.
  3. 각 K 길이의 문자열에서 뉴클레오타이드의 빈도를 검사하고, 가장 작은 빈도를 찾는다.
  4. 모든 문자열을 검사한 후 유효한 비밀번호의 개수와 가장 작은 사전순의 비밀번호를 출력한다.

3. C++ 코딩 예제

아래는 이 문제를 해결하기 위한 C++ 코드 예제입니다:

        #include <iostream>
        #include <string>
        #include <unordered_map>
        #include <vector>
        #include <algorithm>

        using namespace std;

        int main() {
            int N, K;
            string S;
            cin >> N >> K;
            cin >> S;

            unordered_map freq;
            for (int i = 0; i < K; i++) {
                freq[S[i]]++;
            }

            // 초기 결과 설정
            int min_freq = INT_MAX;
            vector passwords;

            // 슬라이딩 윈도우 하여 모든 K 길이 부분 문자열 검사
            for (int i = 0; i <= N - K; i++) {
                if (i > 0) {
                    freq[S[i - 1]]--;
                    freq[S[i + K - 1]]++;
                }

                // 가장 작은 빈도 찾기
                int cur_min = INT_MAX;
                for (const auto &entry : freq) {
                    cur_min = min(cur_min, entry.second);
                }

                // 유효한 비밀번호 추가
                if (cur_min <= (K / 4)) { // 모든 뉴클레오타이드의 빈도가 K/4 이하
                    passwords.push_back(S.substr(i, K));
                }
            }

            // 가장 작은 사전 순의 비밀번호 찾기
            sort(passwords.begin(), passwords.end());
            string smallest_password = (passwords.empty() ? "" : passwords[0]);
            
            // 결과 출력
            cout << passwords.size() << " " << smallest_password << endl;

            return 0;
        }
    

4. 코드 해설

위의 코드는 다음과 같이 작동합니다:

  • 우선 DNA 문자열과 그 길이, 부분 문자열의 길이 K를 입력받습니다.
  • 첫 K개의 문자의 빈도를 카운트하기 위해 unordered_map을 사용합니다.
  • 슬라이딩 윈도우 기법을 사용하여 각 K 길이의 부분 문자열을 이동하면서 빈도를 수정합니다.
  • 각 부분 문자열에 대해 빈도의 최소값을 계산하고, 조건에 맞는 경우에만 유효한 비밀번호 리스트에 추가합니다.
  • 마지막에 유효한 비밀번호 리스트를 정렬하여 가장 작은 사전 순의 비밀번호를 찾습니다.

5. 테스트 케이스

이제 본 문제를 해결하기 위한 몇 가지 테스트 케이스를 살펴보겠습니다:

테스트 케이스 1

        입력:
        8 4
        ACGTTGCA

        출력:
        1 ACGT
    

테스트 케이스 2

        입력:
        12 5
        ACGTTACGATC

        출력:
        3 ACCTA ACTAC TCGAT
    

테스트 케이스 3

        입력:
        6 3
        ACGTAC

        출력:
        2 ACG ACT
    

6. 결론

이번 강좌에서는 DNA 비밀번호 문제를 통해 슬라이딩 윈도우 기법을 활용한 알고리즘을 배웠습니다. 이 기법은 문자열 문제를 해결하는 데 매우 유용하게 사용될 수 있으며, 다양한 변형 문제에 적용할 수 있습니다. 이를 통해 코딩 테스트에서도 채용될 수 있는 좋은 기초 지식이 될 것입니다.

C++ 코딩테스트 강좌, DFS와 BFS 프로그램

본 글에서는 DFS(Depth First Search)와 BFS(Breadth First Search) 알고리즘을 이용한 C++ 코딩 테스트 문제를 해결하는 방법에 대해 설명하겠습니다. 각 알고리즘의 개념 및 특징, 구체적인 코드 예제와 이를 바탕으로 한 문제 풀이 과정을 단계별로 설명하도록 하겠습니다.

1. DFS(Depth First Search) 알고리즘

DFS는 그래프를 탐색하는 알고리즘 중 하나로, 깊이 우선 탐색이라고도 불립니다. 그래프의 한 정점에서 시작해 인접한 정점으로 계속해서 깊이 들어가면서 탐색을 진행합니다. 더 이상 깊이 들어갈 수 없게 되면, 마지막에 방문한 정점으로 돌아가서 다른 인접 정점을 탐색합니다.

1.1 DFS의 특징

  • 스택을 이용한 구현 또는 재귀를 사용하여 쉽게 구현할 수 있습니다.
  • 모든 정점을 한 번씩 방문하므로, 시간 복잡도는 O(V + E)입니다. 여기서 V는 정점의 수, E는 간선의 수입니다.
  • 실행 중 방문한 정점의 정보를 저장해야 하므로, 추가적인 메모리가 필요합니다.

1.2 DFS의 구현

                
#include <iostream>
#include <vector>
#include <stack>

using namespace std;

void DFS(int start, vector &visited, const vector> &adj) {
    stack s;
    s.push(start);

    while (!s.empty()) {
        int node = s.top();
        s.pop();

        if (!visited[node]) {
            visited[node] = true;
            cout << node << ' ';

            for (int i = adj[node].size() - 1; i >= 0; --i) {
                if (!visited[adj[node][i]]) {
                    s.push(adj[node][i]);
                }
            }
        }
    }
}
                
            

2. BFS(Breadth First Search) 알고리즘

BFS는 그래프를 탐색하는 알고리즘 중 하나로, 너비 우선 탐색이라고도 불립니다. 그래프의 한 정점에서 시작해 인접한 모든 정점을 먼저 방문한 후, 그 다음 깊이로 들어가며 탐색을 진행합니다.

2.1 BFS의 특징

  • 큐를 이용하여 구현합니다.
  • 모든 정점을 한 번씩 방문하므로, 시간 복잡도는 O(V + E)입니다.
  • 최단 경로 탐색에 적합한 방법입니다.

2.2 BFS의 구현

                
#include <iostream>
#include <vector>
#include <queue>

using namespace std;

void BFS(int start, vector &visited, const vector> &adj) {
    queue q;
    visited[start] = true;
    q.push(start);

    while (!q.empty()) {
        int node = q.front();
        q.pop();
        cout << node << ' ';

        for (int i = 0; i < adj[node].size(); ++i) {
            if (!visited[adj[node][i]]) {
                visited[adj[node][i]] = true;
                q.push(adj[node][i]);
            }
        }
    }
}
                
            

3. 문제: 그래프 탐색 (DFS 및 BFS 응용)

문제 설명: 주어진 비연결 그래프에서 연결 요소의 개수를 구하는 프로그램을 작성하시오. 그래프의 정점과 간선이 주어질 때, DFS 및 BFS 알고리즘을 사용하여 연결된 정점의 집합을 탐색하여 연결 요소의 개수를 계산합니다.

3.1 입력 형식

첫째 줄에 정점의 수 N (1 <= N <= 1000)과 간선의 수 M (1 <= M <= 100,000)이 주어진다. 다음 M개의 줄에는 간선 정보가 주어진다.

3.2 출력 형식

연결 요소의 개수를 출력한다.

3.3 예제

                
Input:
5 3
1 2
2 3
4 5

Output:
2
                
            

3.4 풀이 과정

이 문제는 DFS와 BFS 알고리즘을 함께 활용하여 연결 요소의 개수를 구할 수 있습니다.

  1. 그래프를 인접 리스트 형태로 표현합니다.
  2. 결방문 정점을 기록할 visited 배열을 초기화합니다.
  3. 정점을 하나씩 순회하며, 방문하지 않은 정점이 발견될 때마다 DFS 또는 BFS를 이용하여 그 정점이 포함된 모든 정점을 방문합니다.
  4. 연결 요소가 발견될 때마다 카운트를 증가시키고, 최종적으로 카운트를 출력합니다.

3.5 C++ 코드 예제

                
#include <iostream>
#include <vector>
#include <stack>
#include <queue>

using namespace std;

void DFS(int start, vector &visited, const vector> &adj) {
    stack s;
    s.push(start);

    while (!s.empty()) {
        int node = s.top();
        s.pop();

        if (!visited[node]) {
            visited[node] = true;

            for (int i = 0; i < adj[node].size(); ++i) {
                if (!visited[adj[node][i]]) {
                    s.push(adj[node][i]);
                }
            }
        }
    }
}

int main() {
    int N, M;
    cin >> N >> M;

    vector> adj(N + 1);
    vector visited(N + 1, false);

    for (int i = 0; i < M; i++) {
        int u, v;
        cin >> u >> v;
        adj[u].push_back(v);
        adj[v].push_back(u); // 무향 그래프이므로 양 방향으로 추가합니다.
    }

    int componentCount = 0;

    for (int i = 1; i <= N; i++) {
        if (!visited[i]) {
            DFS(i, visited, adj);
            componentCount++;
        }
    }

    cout << componentCount << endl;
    
    return 0;
}
                
            

4. 마무리

이번 글에서는 DFS와 BFS 알고리즘을 활용하여 그래프 탐색을 하는 방법과 관련된 문제를 해결해 보았습니다. 각 알고리즘의 특징과 구현 방법, 그리고 문제 해결 과정을 자세히 살펴보았습니다. DFS와 BFS는 그래프 관련 문제에서 매우 중요한 알고리즘이므로, 반복해서 연습하는 것이 중요합니다. 앞으로도 다양한 문제를 해결하며 알고리즘에 대한 이해를 깊이 있게 발전시켜 나가시길 바랍니다.

C++ 코딩테스트 강좌, DDR을 해보자

문제 설명

DDR은 Dance Dance Revolution의 약자로, 플레이어는 화면에 나타나는 화살표에 맞춰서 발을 움직이며 춤을 춥니다.
이 자료구조 및 알고리즘 문제에서는 DDR에서 발생할 수 있는 특정한 상황을 시뮬레이션하고,
입력으로 주어진 화살표 패턴을 기반으로 적절한 움직임을 계산하는 프로그램을 작성해야 합니다.

문제: 주어진 문자열은 화살표 패턴을 나타냅니다. 배열의 각 원소는 화살표의 방향을 나타내며,
‘U’는 위, ‘D’는 아래, ‘L’은 왼쪽, ‘R’은 오른쪽을 의미합니다.
플레이어는 적어도 K개의 화살표를 처리해야 하며, 중복 화살표는 무시해야 합니다.
플레이어가 움직인 방향의 개수를 반환하는 프로그램을 작성하세요.

입력: 문자열과 정수 K (1 ≤ K ≤ 1000)

출력: 플레이어가 움직인 방향의 개수

문제 분석

주어진 문제를 잘 이해하기 위해서는 각 화살표가 어떤 방향으로 가리키는지를 명확히 알고 있어야 합니다.
우리는 중복된 화살표를 고려하지 않아야 하며, 따라서 문자열을 처리하면서 중복된 요소를 원래의 순서대로
고려할 수 있는 데이터 구조가 필요합니다.
화살표의 개수는 유한하며 대문자 ‘U’, ‘D’, ‘L’, ‘R’로만 이루어져 있기 때문에 이 문제는 간단한 문자열 처리로 해결할 수 있습니다.

접근 방법

문제에 접근하기 위해 다음의 단계를 고려할 수 있습니다:

  1. 주어진 문자열을 순회하여 각 화살표를 확인합니다.
  2. 각 화살표를 Set에 추가하여 중복된 화살표를 자동으로 제거합니다.
  3. Set의 크기를 확인하여 플레이어가 실제로 움직인 방향의 개수를 계산합니다.

이 접근 방법은 시간 복잡도가 O(n)이며, n은 주어진 문자열의 길이입니다.
Set을 사용하면 중복을 처리하는 것이 용이하고, 최종적으로 Set의 크기를 얻는 것은 O(1)입니다.

C++ 코드 구현


#include 
#include 
#include 

int processArrows(const std::string &arrows, int K) {
    std::unordered_set uniqueArrows;
  
    // 각 화살표를 순회하면서 Set에 추가
    for (char arrow : arrows) {
        uniqueArrows.insert(arrow);
    }
  
    // K보다 적은 경우에도 상관 없이 Set의 사이즈를 리턴
    return uniqueArrows.size();
}

int main() {
    std::string arrows;
    int K;

    std::cout << "화살표 패턴을 입력하세요: ";
    std::getline(std::cin, arrows);
    std::cout << "K 값을 입력하세요: ";
    std::cin >> K;

    int result = processArrows(arrows, K);
    std::cout << "플레이어가 움직인 방향의 개수: " << result << std::endl;

    return 0;
}
            

코드 설명

위의 C++ 코드는 문제 해결을 위한 간단한 시뮬레이션을 수행합니다.
processArrows 함수는 String과 K를 인자로 받아 화살표를 처리하는 역할을 합니다.
여기서는 unordered_set를 사용하여 중복을 자동으로 제거하고 있습니다.

먼저, 주어진 화살표 문자열을 한 글자씩 순회하면서 각 화살표를 Set에 추가합니다.
Set은 중복된 요소를 허용하지 않기 때문에, 최종적으로 Set의 크기를 통해 플레이어가 실제로
움직인 방향의 개수를 파악할 수 있습니다.

main 함수에서는 사용자로부터 화살표 패턴과 K 값을 입력받고,
그 값을 processArrows 함수에 넘겨 결과를 최종 출력합니다.

결론

본 포스팅에서는 C++를 활용하여 DDR 게임의 간단한 알고리즘 문제를 해결하는 과정을 설명하였습니다.
문제를 단계별로 분석하고 접근 방법을 논의한 후, 최종적으로
효과적인 코드 구현을 통해 문제를 해결할 수 있었습니다.
이러한 접근 방식은 코딩 테스트에서 다루어야 할 여러 알고리즘 문제를 해결하는 데 매우 유용합니다.

C++ 코딩테스트 강좌, Ax + By = C

본 강좌에서는 C++ 언어를 이용하여 Ax + By = C 형태의 방정식을 푸는 방법에 대해 알아보겠습니다.
이 문제는 코딩테스트에서 자주 접할 수 있는 내용으로, 수학적 이해와 알고리즘 설계를 필요로 합니다.

문제 정의

주어진 정수 A, B, C가 있을 때, 방정식 Ax + By = C를 만족하는 정수 x와 y의 모든 조합을 구하는 문제입니다.
주의할 점은 x와 y가 정수여야 한다는 것입니다. 예를 들어 A=2, B=3, C=6일 때,
(x, y) = (0, 2), (3, 0), (1, 1)와 같은 정수 쌍이 있습니다.

문제 해결을 위한 기초 수학 개념

이 문제를 해결하기 위해서는 디오판틴 방정식(Diophantine Equation) 개념을 알아야 합니다.
디오판틴 방정식은 정수 계수를 가진 다항 방정식에서 정수 해를 찾는 문제입니다.
Ax + By = C 형태의 방정식이 일관된 해를 가지려면, gcd(A, B)C의 약수여야 합니다.

알고리즘 설계

1. 먼저 A, B, C의 GCD를 계산합니다.
2. GCD가 C의 약수인지 확인합니다.
3. GCD가 C의 약수이면, x와 y의 가능한 조합을 찾기 시작합니다.
4. 정수 해를 찾기 위해 x의 값은 0부터 시작하여 B로 나눈 나머지를 검토합니다.
5. 각 x에 대해 y를 계산하여 정수 해를 찾습니다.

C++ 코드 구현

아래는 위 알고리즘을 C++로 구현한 예시 코드입니다:

# include <iostream>
# include <vector>
# include <numeric> // for std::gcd
using namespace std;

// Ax + By = C 방정식을 만족하는 (x, y)의 모든 조합을 구하는 함수
void findIntegerSolutions(int A, int B, int C) {
    int gcd_ab = gcd(A, B);

    // GCD가 C의 약수인지 확인
    if (C % gcd_ab != 0) {
        cout << "해가 존재하지 않습니다." << endl;
        return;
    }

    // A, B, C를 GCD로 나누어 정규화
    A /= gcd_ab;
    B /= gcd_ab;
    C /= gcd_ab;

    // x의 가능한 범위를 설정
    for (int x = -100; x <= 100; ++x) {
        // y를 계산
        if ((C - A * x) % B == 0) {
            int y = (C - A * x) / B;
            cout << "(x, y) = (" << x << ", " << y << ")" << endl;
        }
    }
}

int main() {
    int A, B, C;
    cout << "A, B, C 값을 입력하세요: ";
    cin >> A >> B >> C;

    findIntegerSolutions(A, B, C);
    return 0;
}

코드 설명

– 입력으로 A, B, C를 받고 findIntegerSolutions 함수를 호출합니다.
– A, B의 GCD를 계산하여 return하고, 이를 통해 C가 GCD의 약수인지 검사합니다.
– GCD로 모든 수를 나눈 후, x의 값을 -100에서 100까지 변화시키며 y를 계산합니다.
– 방정식이 성립하는 경우 x, y 쌍을 출력합니다.

결과 보기

이제 코드 실행 결과를 확인해보겠습니다. 예를 들어 A=2, B=3, C=6인 경우 다음과 같은 결과를 얻을 수 있습니다:

A, B, C 값을 입력하세요: 2 3 6
(x, y) = (0, 2)
(x, y) = (3, 0)
(x, y) = (1, 1)

결론

이번 강좌에서는 Ax + By = C 형태의 방정식을 C++로 해결하는 방법을 살펴보았습니다.
이 문제를 통해 디오판틴 방정식의 기초 이론과, 이를 해결하기 위한 알고리즘 설계를 익히게 되었습니다.
이러한 문제는 코딩테스트에서 자주 출제되므로, 충분히 연습하셔서 자신만의 풀이 방법을 찾는 것이 중요합니다.