Computer >> 컴퓨터 >  >> 프로그래밍 >> C++

C++로 배열의 모든 요소를 제거하기 위한 최소 연산 횟수 구하기


문제 설명

크기가 짝수인 N개의 정수로 이루어진 배열이 주어졌을 때, 이 배열에는 다음 두 가지 연산을 적용할 수 있습니다.

  • 배열에 있는 임의의 요소 값을 1만큼 증가시킵니다.
  • 배열에서 인접한 두 요소가 서로 연속하는 소수(예: 11과 13)일 경우, 두 요소를 동시에 삭제합니다.

이 문제의 목표는 배열의 모든 요소를 제거하기 위해 필요한 최소 연산 횟수를 구하는 것입니다.

예시

배열이 {10, 13}이라면 최소 2번의 연산만으로 모든 요소를 제거할 수 있습니다.

  • 첫 번째 요소의 값을 1 증가시켜 배열을 {11, 13}으로 만듭니다.
  • 11과 13은 서로 연속하는 소수이므로, 첫 번째와 두 번째 요소를 한 번에 삭제합니다.

알고리즘

1. 두 수를 제거하려면 먼저 두 수를 서로 연속하는 소수 쌍으로 변환해야 합니다.
2. a와 b가 연속하는 소수라고 가정할 때, 에라토스테네스의 체(Sieve of Eratosthenes)를 사용해 소수를 미리 계산해 둔 후, a 이하에서 가장 큰 소수 p와 p보다 큰 다음 소수를 찾습니다.
3. 위 계산이 완료되면 동적 계획법(Dynamic Programming)을 적용해 전체 문제의 최솟값을 구합니다.

C++ 구현 코드

다음은 큐(queue)와 너비 우선 탐색(BFS) 기법을 활용해 가능한 상태들을 탐색하면서 최소 연산 횟수를 찾아내는 C++ 예제 코드입니다.

#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
int minimumPrefixReversals(int *a, int n) {
    string start = "";
    string destination = "", t, r;
    for (int i = 0; i < n; i++) {
        start += to_string(a[i]);
    }
    sort(a, a + n);
    for (int i = 0; i < n; i++) {
        destination += to_string(a[i]);
    }
    queue<pair<string, int> > qu;
    pair<string, int> p;
    qu.push(make_pair(start, 0));
    if (start == destination) {
        return 0;
    }
    while (!qu.empty()) {
        p = qu.front();
        t = p.first;
        qu.pop();
        for (int j = 2; j <= n; j++) {
            r = t;
            reverse(r.begin(), r.begin() + j);
            if (r == destination) {
                return p.second + 1;
            }
            qu.push(make_pair(r, p.second + 1));
        }
    }
}
int main() {
    int a[] = { 1, 2, 4, 3 };
    int n = sizeof(a) / sizeof(a[0]);
    cout << "Minimum reversal: " <<
    minimumPrefixReversals(a, n) << endl;
    return 0;
}

위 프로그램을 컴파일하여 실행하면 다음과 같은 결과가 출력됩니다.

출력 결과

Minimum reversal: 3