자료구조&알고리즘/C++

🚀 재귀를 활용한 완전 탐색 vs 백트래킹 비교!

geminanolja 2025. 3. 4. 20:53

📌 1️⃣ 완전 탐색

"완전 탐색(Brute Force)" 방식으로 모든 경우를 확인하면서 합을 11로 나눈 나머지(mod 11)의 최댓값을 찾는 코드


📌 2️⃣ 코드 흐름 분석

void findMaxMod(int index, int sum) 
{
    // 🎯 모든 숫자를 확인했을 때 (모든 경우를 시도한 후)
    if (index == N) 
    {
        maxMod = max(maxMod, sum % 11);  // 최댓값 갱신
        return;
    }

    // 1️⃣ 현재 숫자를 선택하는 경우
    findMaxMod(index + 1, sum + numbers[index]);

    // 2️⃣ 현재 숫자를 선택하지 않는 경우
    findMaxMod(index + 1, sum);
}

📌 3️⃣ 코드 실행 과정 (예제 입력)

입력 예시 (N=4, numbers = {24, 35, 38, 40})

N = 4
numbers = {24, 35, 38, 40}

📌 4️⃣ 재귀 호출 과정

📍 findMaxMod(0, 0) 실행

  • 첫 번째 숫자 24를 선택할지 말지 결정해야 함!

호출된 함수 선택한 숫자 현재 합 재귀 호출

findMaxMod(0, 0) {} 0 숫자 선택 O → findMaxMod(1, 24)
findMaxMod(0, 0) {} 0 숫자 선택 X → findMaxMod(1, 0)

📍 findMaxMod(1, 24) 실행

  • 두 번째 숫자 35를 선택할지 말지 결정해야 함!

호출된 함수 선택한 숫자 현재 합 재귀 호출

findMaxMod(1, 24) {24} 24 숫자 선택 O → findMaxMod(2, 59)
findMaxMod(1, 24) {24} 24 숫자 선택 X → findMaxMod(2, 24)

📍 이 과정이 계속 반복되어, 2^N 개의 경우를 모두 확인

예제 입력 (N=4)인 경우,

  • 총 2⁴ = 16번의 경우의 수를 탐색해야 함!

즉, 모든 경우를 다 시도하면서 최적의 mod 11 값을 찾는 방법!


🚀 5️⃣ 백트래킹을 사용하면 뭐가 다를까?

백트래킹(Backtracking)은 "불필요한 경우의 수를 미리 제거"하는 기법!


📌 6️⃣ 백트래킹 코드 (불필요한 탐색 제거)

void findMaxMod(int index, int sum) 
{
    // 🎯 만약 현재 sum이 이미 maxMod보다 작다면 더 탐색할 필요 없음!
    if (sum % 11 < maxMod) return;  

    if (index == N) 
    {
        maxMod = max(maxMod, sum % 11);
        return;
    }

    // 1️⃣ 현재 숫자를 선택하는 경우
    findMaxMod(index + 1, sum + numbers[index]);

    // 2️⃣ 현재 숫자를 선택하지 않는 경우
    findMaxMod(index + 1, sum);
}

📌 7️⃣ 완전 탐색 vs 백트래킹 차이

완전 탐색 백트래킹

방법 모든 경우를 탐색 불필요한 경우 제거
시간 복잡도 O(2^N) O(2^N)보다 더 적음
불필요한 탐색 많음 (모든 경우 시도) 적음 (필요한 경우만 탐색)
최적화 X (비효율적) O (효율적)

📌 8️⃣ 백트래킹의 효과

불필요한 탐색을 줄여서 실행 속도를 빠르게 함!
하지만 문제에 따라 백트래킹이 적용되지 않을 수도 있음!
경우의 수가 많아질수록 백트래킹이 훨씬 유리함!

 

 

#include <iostream>
#include <vector>
using namespace std;

int N, maxMod = 0;
int  cnt = 1;
vector<int> numbers;

// ✅ 재귀 함수: 현재 index에서 숫자를 선택하거나 선택하지 않는 방식
void findMaxMod(int index, int sum) 
{
    if (sum % 11 < maxMod) return;
    //if (maxMod == 10) return;

    // 🎯 모든 숫자를 확인했을 때, mod 11 값 업데이트
    if (index == N) 
    {
        maxMod = max(maxMod, sum % 11);
        return;
    }
    cnt++;
    //1.현재 숫자를 선택하는 경우
    findMaxMod(index + 1, sum + numbers[index]);

    //2. 현재 숫자를 선택하지 않는 경우
    findMaxMod(index + 1, sum);
}

int main() {
    // 🔹 입력 받기a
    cin >> N;
    numbers.resize(N);
    for (int i = 0; i < N; i++) 
    {
        cin >> numbers[i];
    }

    // 🚀 완전 탐색 시작 (재귀 함수 호출)
    findMaxMod(0, 0);

    // 🔹 최종 결과 출력
    cout << "가장 큰 mod 11 값: " << maxMod << endl;
    cout << "cnt : " << cnt << endl;

    return 0;
}

if (sum % 11 < maxMod) return;
이 한줄의 추가 만으로 1024번 반복이 16번으로 줄어듬