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

원형으로 배치된 상자에서 모든 돌을 제거할 수 있는지 확인하는 C++ 프로그램

문제 설명

N개의 요소를 가진 배열 A가 있다고 가정해 보겠습니다. N개의 상자가 하나의 원을 이루며 배치되어 있고, i번째 상자에는 A[i]개의 돌이 들어 있습니다. 우리는 다음 연산을 반복 수행하여 모든 상자에서 돌을 완전히 비울 수 있는지 확인해야 합니다.

  • 임의의 상자 i를 하나 선택합니다.
  • j가 1부터 N까지 변하는 동안, (i+j)번째 상자에서 정확히 j개의 돌을 제거합니다. 이때 (N+k)번째 상자는 k번째 상자와 동일하게 취급합니다(원형 순환).
  • 만약 어떤 상자에 충분한 돌이 들어 있지 않다면 해당 연산은 수행할 수 없습니다.

예를 들어 입력이 A = [4, 5, 1, 2, 3]이라면 출력은 True가 됩니다. 두 번째 상자에서 시작하면 모든 돌을 제거할 수 있기 때문입니다.

해결 접근 방법

이 문제는 수학적 성질을 활용하면 효율적으로 해결할 수 있습니다.

연산을 한 번 수행할 때마다 1 + 2 + … + N = N(N+1)/2개의 돌이 제거됩니다. 따라서 전체 돌의 개수는 반드시 p = N(N+1)/2로 나누어떨어져야 하며, 그 몫 k는 연산을 수행해야 하는 횟수가 됩니다.

그다음에는 인접한 상자들 사이의 돌 개수 차이를 이용해 추가 조건을 검증합니다. 모든 차이 값의 합이 0이어야 하고, 각 상자에 대해 (차이 + k)가 N으로 나누어떨어지면서 동시에 음수가 아니어야 합니다. 이 조건들을 모두 통과하면 모든 돌을 제거하는 것이 가능합니다.

단계별 과정을 정리하면 다음과 같습니다.

  1. n을 배열 A의 크기로 설정합니다.
  2. 크기가 (n+1)인 배열 a와 b를 선언합니다.
  3. sum := 0, p := n * (n + 1) / 2로 초기화합니다.
  4. i가 1부터 n까지 증가하는 동안 a[i] := A[i-1]을 대입하고 sum에 누적합니다.
  5. sum을 p로 나눈 나머지가 0이 아니라면 false를 반환합니다.
  6. k := sum / p로 설정합니다.
  7. i가 1부터 n까지 증가하는 동안 b[i] := a[i] - a[(i mod n) + 1]을 계산합니다.
  8. 배열 b의 값을 다시 a에 옮겨 담으면서 합을 구하고, 그 합이 0이 아니면 false를 반환합니다.
  9. 모든 i에 대해 (a[i] + k)가 n으로 나누어떨어지지 않거나 a[i] + k가 음수라면 false를 반환합니다.
  10. 위 조건을 모두 통과하면 true를 반환합니다.

예제 코드

아래 C++ 구현을 통해 좀 더 자세히 이해해 보겠습니다.

#include <bits/stdc++.h>
using namespace std;
bool solve(vector<int> A) {
    int n = A.size();
    vector<int> a(n + 1);
    vector<int> b(n + 1);
    int sum = 0, p = n * (n + 1) / 2;
    for (int i = 1; i <= n; i++) {
        a[i] = A[i - 1];
        sum += a[i];
    }
    if (sum % p != 0) {
        return false;
    }
    int k = sum / p;
    for (int i = 1; i <= n; i++) {
        b[i] = a[i] - a[i % n + 1];
    }
    sum = 0;
    for (int i = 1; i <= n; i++) {
        a[i] = b[i];
        sum += a[i];
    }
    if (sum != 0) {
        return false;
    }
    for (int i = 1; i <= n; i++) {
        if ((a[i] + k) % n != 0 || a[i] + k < 0) {
            return false;
        }
    }
    return true;
}
int main(){
    vector<int> A = { 4, 5, 1, 2, 3 };
    cout << solve(A) << endl;
}

입력

{ 4, 5, 1, 2, 3 }

출력

1

출력값 1은 true를 의미합니다. 즉, 두 번째 상자에서 시작해 연산을 반복하면 모든 상자의 돌을 성공적으로 제거할 수 있다는 뜻입니다.